home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / DOMAIN.C < prev    next >
C/C++ Source or Header  |  1997-08-18  |  72KB  |  2,831 lines

  1. /*
  2.  *      DOMAIN.C -- domain name system stub resolver
  3.  *
  4.  *      Original code by Phil Karn, KA9Q
  5.  *
  6.  *      04-90 -- Bill Simpson added address->name resolution, time-to-live,
  7.  *      thru     memory caching, generalized multi-record multi-type searches,
  8.  *      10-90    and many minor changes to conform more closely to the RFCs.
  9.  *
  10.  *  06-89 -- Gerard van der Grinten, PA0GRI
  11.  *      thru     Lots of changes and inprovements including server code.
  12.  *      02-91
  13.  *
  14.  *  Jan 92  Bill Simpson added CNAME support to domainsuffix routine.
  15.  *
  16.  *  Jun 92  Johan. K. Reinalda, WG7J
  17.  *          Ported the Domain Name Server from PA0GRI's 910828 .
  18.  *          Version info see down below
  19.  *
  20.  */
  21.  
  22. #include "global.h"
  23. #include "ctype.h"
  24. #include "commands.h"
  25. #ifndef MSDOS
  26. #include <time.h>
  27. #endif
  28. #include <sys/stat.h>
  29. #include "mbuf.h"
  30. #include "netuser.h"
  31. #include "ip.h"
  32. #include "domain.h"
  33. #include "files.h"
  34. #include "session.h"
  35.  
  36. #if !defined(_lint)
  37. static char rcsid[] OPTIONAL = "$Id: domain.c,v 1.34 1997/08/19 01:19:22 root Exp root $";
  38. #endif
  39.  
  40. #ifdef UNIX
  41. /*lint -esym(534, tfprintf) -esym(652, fprintf, printf) */
  42. #undef  fprintf
  43. #define fprintf tfprintf
  44. #undef  printf
  45. #define printf tprintf
  46. #endif
  47.  
  48. #undef  DEBUG            /* for certain trace messages */
  49. #undef  DEBUG_PAIN        /* for painful debugging */
  50.  
  51. extern int main_exit;        /* from main program (flag) */
  52. extern int Mprunning;        /* from main program (flag) */
  53. extern int Mprunning_err;    /* from main program (flag) */
  54. int DTranslate;            /* do IP address to domain name translation */
  55. int DVerbose;            /* Use all of resolved name or first element */
  56. static int DTransing;        /* flag that says we are translating        */
  57. static int DLTranslate;        /* translate using LOCAL domain.txt ONLY    */
  58.  
  59.  
  60. static struct rr *Dcache;    /* Cache of resource records */
  61. static int Dcache_size = 20;    /* size limit */
  62. static time_t Dcache_time = 0L;    /* timestamp */
  63.  
  64. static int Dfile_clean;        /* discard expired records (flag) */
  65. static int Dfile_reading;    /* read interlock (count) */
  66. static int Dfile_writing;    /* write interlock (count) */
  67.  
  68. struct proc *Dfile_updater;
  69. static int32 Dfile_wait_absolute;    /* timeout Clock time */
  70. static int Dfile_wait_relative = 300;    /* timeout file activity (seconds) */
  71.  
  72. static struct dserver *Dservers;/* List of potential servers */
  73. static int Dserver_retries = 3;    /* Attempts to reach servers */
  74. static int32 Dserver_maxwait = 60L;    /* maximum server timeout limit (seconds) */
  75.  
  76. /* KG7CP -  */
  77. static int Dfile_upd = 0;    /* update the domain file (flag) */
  78.  
  79. #ifdef DSERVER
  80. static int32 Dns_ttl = 0L;    /* time-to-live of dns answers */
  81. static int dns_maxcli = 6;    /* max number of simultaneous DNS processes */
  82. static int dns_process_count = 0;
  83. #endif
  84.  
  85. /* N7IPB */
  86. static int Dsubnet_translate;    /* Translate subnet and broadcast addresses */
  87.  
  88. static char *Dsuffix;        /* Default suffix for names without periods */
  89. static int Dsuffixl;        /* size of Dsuffix (less computing to do */
  90. static int Dtrace;
  91. static const char *Dtypes[] =
  92. {
  93.     "",
  94.     "A",
  95.     "NS",
  96.     "MD",
  97.     "MF",
  98.     "CNAME",
  99.     "SOA",
  100.     "MB",
  101.     "MG",
  102.     "MR",
  103.     "NULL",
  104.     "WKS",
  105.     "PTR",
  106.     "HINFO",
  107.     "MINFO",
  108.     "MX",
  109.     "TXT"
  110. };
  111.  
  112. #define NDTYPES 17
  113.  
  114. #ifdef DSERVER
  115. /* Following array used by domain query for type field */
  116.  
  117. static const char *Dtypes1[] =
  118. {
  119.  
  120.     "A",        "1",        /* Host address */
  121.     "NS",        "2",        /* Name server */
  122.     "MD",        "3",        /* Mail destination (obsolete) */
  123.     "MF",        "4",        /* Mail forwarder (obsolete) */
  124.     "CNAME",    "5",        /* Canonical name */
  125.     "SOA",        "6",        /* Start of Authority */
  126.     "MB",        "7",        /* Mailbox name (experimental) */
  127.     "MG",        "8",        /* Mail group member (experimental) */
  128.     "MR",        "9",        /* Mail rename name (experimental) */
  129.     "NULL",        "10",        /* Null (experimental) */
  130.     "WKS",        "11",        /* Well-known sockets */
  131.     "PTR",        "12",        /* Pointer record */
  132.     "HINFO",    "13",        /* Host information */
  133.     "MINFO",    "14",        /* Mailbox information (experimental)*/
  134.     "MX",        "15",        /* Mail exchanger */
  135.     "TXT",        "16",        /* Text strings */
  136.     "AXFR",        "252",        /* Transfer zone of authority */
  137.     "MAILB",    "253",        /* Transfer mailbox records */
  138.     "MAILA",    "254",        /* Transfer mail agent records */
  139.     "ANY",        "255"        /* Matches any type */
  140. };
  141. #endif
  142.  
  143. #define NDTYPES1    40
  144.  
  145. #ifndef TNOS_68K
  146. static const char delim[] = " \t\r\n";
  147. #else
  148. static const char delim[] = " \t\r\l";
  149. #endif
  150.  
  151. #ifdef DSERVER
  152. static int dodomresolve (int argc, char *argv[], void *p);
  153. static int dodnsquery (int argc, char *argv[], void *p);
  154. #endif /* DSERVER */
  155.  
  156. static struct rr *resolve_rr (const char *dname,int16 dtype,int recurse);
  157. static int docache (int argc, char *argv[], void *p);
  158. static int dosuffix (int argc, char *argv[], void *p);
  159. static int dotranslate (int argc, char *argv[], void *p);
  160. static int doverbose (int argc, char *argv[], void *p);
  161. static int docacheclean (int argc, char *argv[], void *p);
  162. static int docachelist (int argc, char *argv[], void *p);
  163. static int docachesize (int argc, char *argv[], void *p);
  164. static int docachewait (int argc, char *argv[], void *p);
  165. static int dofileupdate (int argc, char *argv[], void *p);
  166. static int docachedump (int argc, char *argv[], void *p);
  167. static int dosubnettrans (int argc, char *argv[], void *p);
  168. static void dlist_add (struct dserver * dp);
  169. static void dlist_drop (struct dserver * dp);
  170. static int dodnsadd (int argc, char *argv[], void *p);
  171. static int dodnsdrop (int argc, char *argv[], void *p);
  172. static int dodnslist (int argc, char *argv[], void *p);
  173. static int dodnsmaxw (int argc, char *argv[], void *p);
  174. static int dodnsretry (int argc, char *argv[], void *p);
  175. static int dodnstrace (int argc, char *argv[], void *p);
  176. static int dodomlook (int argc, char *argv[], void *p);
  177. static int dolocaltrans (int argc, char *argv[], void *p);
  178. static int check_ttl (struct rr * rrlp);
  179. static int compare_rr (struct rr * search_rrp, struct rr * target_rrp);
  180. static int compare_rr_list (struct rr * rrlp, struct rr * target_rrp);
  181. static struct rr *copy_rr (struct rr * rrp);
  182. static struct rr *copy_rr_list (struct rr * rrlp);
  183. static struct rr *make_rr (int source,
  184.     char *dname, int16 class, int16 type, int32 ttl, int16 rdl, void *data);
  185. static void dcache_add (struct rr * rrlp);
  186. static void dcache_drop (struct rr * rrp);
  187. static struct rr *dcache_search (struct rr * rrlp);
  188. static void dcache_update (struct rr * rrlp);
  189. static struct rr *get_rr (FILE * fp, struct rr * lastrrp);
  190. static void put_rr (FILE * fp, struct rr * rrp);
  191. static struct rr *dfile_search (struct rr * rrlp);
  192. static struct rr *dfile_search_file (struct rr * rrlp, const char *filename);
  193. static void dfile_update (int s, void *unused, void *p);
  194. static void dumpdomain (struct dhdr * dhp, int32 rtt);
  195. static int dns_makequery (int16 op, struct rr * rrp, char *buffer, int16 buflen);
  196. static void dns_query (struct rr * rrlp);
  197. static int isaddr (const char *s);
  198. static struct rr *resolver (struct rr * rrlp);
  199.  
  200. #ifdef DSERVER
  201. static void free_dhdr (struct dhdr *);
  202. static int dodns_ttl (int argc, char *argv[], void *p);
  203. static int dodnsserver (int argc, char *argv[], void *p);
  204. static int dodnsmaxcli (int argc, char *argv[], void *p);
  205. static void proc_query (int, void *, void *);
  206. static void drx (int, void *, void *);
  207. #endif
  208.  
  209. /**
  210.  **     Domain Resolver Commands
  211.  **/
  212.  
  213. static struct cmds Dcmds[] =
  214. {
  215.     { "addserver",    dodnsadd,    0, 2, "domain addserver <hostid>" },
  216.     { "cache",    docache,    0, 0, NULLCHAR },
  217. #ifdef DSERVER
  218.     { "dns",    dodnsserver,    0, 0, NULLCHAR },
  219. #endif
  220.     { "dropserver",    dodnsdrop,    0, 2, "domain dropserver <hostid>" },
  221.     { "list",    dodnslist,    0, 0, NULLCHAR },
  222.     { "localtrans",    dolocaltrans,    0, 0, NULLCHAR },
  223. #ifdef ALLCMD
  224.     { "look",    dodomlook,    512, 2, "domain look \"<search text>\"" },
  225. #endif
  226. #ifdef DSERVER
  227.     { "maxclients",    dodnsmaxcli,    0, 0, NULLCHAR },
  228. #endif
  229.     { "maxwait",    dodnsmaxw,    0, 0, NULLCHAR },
  230. #ifdef DSERVER
  231.     { "query",    dodnsquery,   512, 3, "domain query <dns hostid> <hostid> [type] [maxtries] [timeout-ms]" },
  232.     { "resolve",    dodomresolve, 512, 2, "domain resolve <hostid>" },
  233. #endif /* DSERVER */
  234.     { "retries",    dodnsretry,    0, 0, NULLCHAR },
  235.     { "subnet",    dosubnettrans,    0, 0, NULLCHAR },
  236.     { "suffix",    dosuffix,    0, 0, NULLCHAR },
  237.     { "trace",    dodnstrace,    0, 0, NULLCHAR },
  238.     { "translate",    dotranslate,    0, 0, NULLCHAR },
  239. #ifdef DSERVER
  240.     { "ttl",    dodns_ttl,    0, 0, NULLCHAR },
  241. #endif
  242.     { "update",    dofileupdate,    0, 0, NULLCHAR },
  243.     { "verbose",    doverbose,    0, 0, NULLCHAR },
  244.     { NULLCHAR,    NULL,        0, 0, NULLCHAR }
  245. };
  246.  
  247.  
  248. static struct cmds Dcachecmds[] =
  249. {
  250.     { "clean",    docacheclean,    0, 0, NULLCHAR },
  251.     { "dump",    docachedump,    0, 0, NULLCHAR },
  252.     { "flush",    docachedump,    0, 0, NULLCHAR },
  253.     { "list",    docachelist,  512, 0, NULLCHAR },
  254.     { "size",    docachesize,    0, 0, NULLCHAR },
  255.     { "wait",    docachewait,    0, 0, NULLCHAR },
  256.     { NULLCHAR,    NULL,        0, 0, NULLCHAR }
  257. };
  258.  
  259.  
  260.  
  261. int
  262. dodomain (int argc, char *argv[], void *p)
  263. {
  264.     return subcmd (Dcmds, argc, argv, p);
  265. }
  266.  
  267.  
  268.  
  269. int
  270. docache (int argc, char *argv[], void *p)
  271. {
  272.     return subcmd (Dcachecmds, argc, argv, p);
  273. }
  274.  
  275.  
  276.  
  277. static int
  278. dosuffix (int argc, char *argv[], void *p OPTIONAL)
  279. {
  280.     if (argc < 2) {
  281.         if (Dsuffix != NULLCHAR)
  282.             tprintf ("%s\n", Dsuffix);
  283.         else
  284.             tputs ("No domain suffix defined.\n");
  285.         return 0;
  286.     }
  287.     if (strcmp (argv[1], "none") == 0) {
  288.         if (Dsuffix != NULLCHAR) {
  289.             free (Dsuffix);
  290.             Dsuffix = NULLCHAR;    /* clear out suffix */
  291.             Dsuffixl = 0;
  292.         }
  293.     } else if (argv[1][strlen (argv[1]) - 1] != '.') {
  294.         tprintf (" %s is not a valid suffix.\n", argv[1]);
  295.         return 1;
  296.     } else {
  297.         if (Dsuffix != NULLCHAR)
  298.             free (Dsuffix);
  299.         Dsuffix = strdup (argv[1]);
  300.         Dsuffixl = (int) strlen (Dsuffix);
  301.     }
  302.     return 0;
  303. }
  304.  
  305.  
  306.  
  307. static int
  308. dolocaltrans (int argc, char *argv[], void *p OPTIONAL)
  309. {
  310.     return setbool (&DLTranslate, "Translate IP address only using LOCAL domain.txt", argc, argv);
  311. }
  312.  
  313.  
  314.  
  315. static int
  316. dotranslate (int argc, char *argv[], void *p OPTIONAL)
  317. {
  318.     return setbool (&DTranslate, "Translate IP address to host names", argc, argv);
  319. }
  320.  
  321.  
  322.  
  323. static int
  324. doverbose (int argc, char *argv[], void *p OPTIONAL)
  325. {
  326.     return setbool (&DVerbose, "Verbose translation of host names", argc, argv);
  327. }
  328.  
  329.  
  330.  
  331. static int
  332. dodnsmaxw (int argc, char *argv[], void *p OPTIONAL)
  333. {
  334.     return setlong (&Dserver_maxwait, "Server response timeout limit (sec)", argc, argv);
  335. }
  336.  
  337.  
  338.  
  339. static int
  340. docacheclean (int argc, char *argv[], void *p OPTIONAL)
  341. {
  342.     return setbool (&Dfile_clean, "Discard expired records", argc, argv);
  343. }
  344.  
  345.  
  346.  
  347. #ifdef DSERVER
  348. /*KG7CP -  set the standard time-to-live for nameserver answers */
  349. static int
  350. dodns_ttl (int argc, char *argv[], void *p OPTIONAL)
  351. {
  352.     return setlong (&Dns_ttl, "Time-to-live of nameserver answers (secs)", argc, argv);
  353. }
  354. #endif
  355.  
  356.  
  357.  
  358. /* KG7CP -   remove all entries from the cache */
  359. static int
  360. docachedump (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  361. {
  362. struct rr *dump_rrlp;
  363.  
  364.     dump_rrlp = Dcache;
  365.     Dcache = NULLRR;
  366.     free_rr (dump_rrlp);
  367.     return 0;
  368. }
  369.  
  370.  
  371.  
  372. /* KG7CP -  flag whether the domain file is updated from name server
  373.  * quey responses
  374.  */
  375. static int
  376. dofileupdate (int argc, char *argv[], void *p OPTIONAL)
  377. {
  378.     return setbool (&Dfile_upd, "Update Domain file", argc, argv);
  379. }
  380.  
  381.  
  382.  
  383. /* N7IPB - Enable or Disable translation of subnet and broadcast addresses */
  384. static int
  385. dosubnettrans (int argc, char *argv[], void *p OPTIONAL)
  386. {
  387.     return setbool (&Dsubnet_translate, "Translate IP subnet and broadcast addresses", argc, argv);
  388. }
  389.  
  390.  
  391.  
  392. static int
  393. docachelist (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  394. {
  395. struct rr *rrp;
  396. char tmpname[80];
  397. FILE *fp;
  398. char **margv;
  399. int count = 0;
  400.  
  401.     margv = (char **) callocw (2, sizeof (char *));
  402.  
  403.     (void) tmpnam (tmpname);
  404.     fp = fopen (tmpname, WRITE_TEXT);
  405.     if (fp)    {
  406.         (void) dcache_search (NULLRR);    /* update ttl */
  407. #ifndef UNIX
  408.         rflush ();
  409. #endif
  410.         for (rrp = Dcache; rrp != NULLRR; rrp = rrp->next) {
  411.             ++count;
  412.             put_rr (fp, rrp);
  413.         }
  414.         (void) fclose (fp);
  415.     }
  416.     if (count) {
  417.         margv[1] = strdup (tmpname);
  418.         (void) morecmd (2, margv, p);
  419.         free (margv[1]);
  420.         free (margv);
  421.     } else
  422.         tputs ("Cache Empty\n");
  423.  
  424.     unlink (tmpname);
  425.     return 0;
  426. }
  427.  
  428.  
  429.  
  430. static int
  431. docachesize (int argc, char *argv[], void *p OPTIONAL)
  432. {
  433. int newsize;
  434. int oldsize;
  435. int result;
  436.  
  437.     newsize = oldsize = Dcache_size;
  438.     result = setint (&newsize, "Domain memory cache size", argc, argv);
  439.  
  440.     if (newsize > 0) {
  441.         Dcache_size = newsize;
  442.         if (newsize < oldsize)
  443.             (void) dcache_search (NULLRR);    /* update size */
  444.     }
  445.     return result;
  446. }
  447.  
  448.  
  449.  
  450. static int
  451. docachewait (int argc, char *argv[], void *p OPTIONAL)
  452. {
  453.     return setint (&Dfile_wait_relative, "Time before Domain file update (secs)", argc, argv);
  454. }
  455.  
  456.  
  457.  
  458. static void
  459. dlist_add (register struct dserver *dp)
  460. {
  461.     dp->prev = NULLDOM;
  462.     dp->next = Dservers;
  463.     if (Dservers != NULLDOM)
  464.         Dservers->prev = dp;
  465.     Dservers = dp;
  466. }
  467.  
  468.  
  469.  
  470. static void
  471. dlist_drop (register struct dserver *dp)
  472. {
  473.     if (dp->prev != NULLDOM)
  474.         dp->prev->next = dp->next;
  475.     else
  476.         Dservers = dp->next;
  477.     if (dp->next != NULLDOM)
  478.         dp->next->prev = dp->prev;
  479. }
  480.  
  481.  
  482.  
  483. static int
  484. dodnsadd (int argc, char *argv[], void *p OPTIONAL)
  485. {
  486. uint32 address;
  487. int timeout = 0;
  488.  
  489.     if ((address = resolve (argv[1])) == 0L) {
  490.         tprintf ("Domain Nameserver %s unknown\n", argv[1]);
  491.         return 1;
  492.     }
  493.     if (argc > 2 && argv[2])
  494.         timeout = atoi (argv[2]);
  495.     return add_nameserver (address, timeout);
  496. }
  497.  
  498.  
  499. int
  500. add_nameserver (uint32 address, int timeout)
  501. {
  502. struct dserver *dp;
  503.  
  504.     dp = (struct dserver *) callocw (1, sizeof (struct dserver));
  505.  
  506.     dp->address = address;
  507.     if (timeout)
  508.         dp->srtt = timeout * 1000L;
  509.     else
  510.         dp->srtt = 3 * Tcp_irtt;    /* Round trip plus processing time */
  511.     dp->mdev = 0;
  512.     dp->timeout = dp->srtt;    /* 4 * dp->mdev + dp->srtt;*/
  513.     dlist_add (dp);
  514.     return 0;
  515. }
  516.  
  517.  
  518.  
  519. static int
  520. dodnsdrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  521. {
  522. struct dserver *dp;
  523. uint32 addr;
  524.  
  525.     addr = resolve (argv[1]);
  526.     for (dp = Dservers; dp != NULLDOM; dp = dp->next)
  527.         if (addr == dp->address)
  528.             break;
  529.  
  530.     if (dp == NULLDOM) {
  531.         tputs ("DNS not found\n");
  532.         return 1;
  533.     }
  534.     dlist_drop (dp);
  535.     free ((char *) dp);
  536.     return 0;
  537. }
  538.  
  539.  
  540.  
  541. static int
  542. dodnslist (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  543. {
  544. register struct dserver *dp;
  545.  
  546.     tputs ("Server address          SRTT    Mdev    Timeout  Queries Responses Timeouts\n");
  547.     for (dp = Dservers; dp != NULLDOM; dp = dp->next)
  548.         tprintf ("%-20s%8lu%8lu%10lu%10lu%10lu%10lu\n",
  549.             inet_ntoa (dp->address), dp->srtt, dp->mdev,
  550.             dp->timeout, dp->queries, dp->responses, dp->timeouts);
  551.     return 0;
  552. }
  553.  
  554.  
  555.  
  556. static int
  557. dodnsretry (int argc, char *argv[], void *p OPTIONAL)
  558. {
  559.     return setint (&Dserver_retries, "DNS retry limit", argc, argv);
  560. }
  561.  
  562.  
  563.  
  564. static int
  565. dodnstrace (int argc, char *argv[], void *p OPTIONAL)
  566. {
  567.     return setbool (&Dtrace, "DNS tracing", argc, argv);
  568. }
  569.  
  570.  
  571.  
  572. /**
  573.  **     Domain Resource Record Utilities
  574.  **/
  575.  
  576. /* check list of resource records for any expired ones.
  577.  * returns number of expired records.
  578.  */
  579. static int
  580. check_ttl (register struct rr *rrlp)
  581. {
  582. int count = 0;
  583.  
  584.     while (rrlp != NULLRR) {
  585.         if (rrlp->ttl == 0L)
  586.             count++;
  587.         rrlp = rrlp->next;
  588.     }
  589.     return count;
  590. }
  591.  
  592.  
  593.  
  594. /* Compare two resource records.
  595.  * returns 0 if match, nonzero otherwise.
  596.  */
  597. static int
  598. compare_rr (register struct rr *search_rrp, register struct rr *target_rrp)
  599. {
  600. int i, j, k;
  601.  
  602.     if (search_rrp == NULLRR || target_rrp == NULLRR)
  603.         return -32765;
  604.  
  605.     if (search_rrp->class != target_rrp->class)
  606.         return -32763;
  607.  
  608.     if (search_rrp->type != target_rrp->type && (search_rrp->source != RR_QUERY
  609.         || (target_rrp->type != TYPE_CNAME && target_rrp->type != TYPE_PTR)))
  610.         return -32761;
  611.  
  612.     if (search_rrp->source != RR_INQUERY) {
  613.         /* added to prevent dereferencing null names - shouldn't happen */
  614.         if (!search_rrp->name || !target_rrp->name)
  615.             return -32764;
  616.         i = (int) strlen (search_rrp->name);
  617.         j = (int) strlen (target_rrp->name);
  618.         if (i == j) {
  619.             if ((k = strnicmp (search_rrp->name, target_rrp->name, (unsigned) i)) != 0)
  620.                 return k;
  621.         } else {
  622.             if (Dsuffix != NULLCHAR) {
  623.                 if (i != j + Dsuffixl + 1)
  624.                     return -32759;
  625.                 else {
  626.                     if (search_rrp->name[j] != '.')
  627.                         return -32755;
  628.                     if (strnicmp (target_rrp->name
  629.                               ,search_rrp->name, (unsigned) j) != 0)
  630.                         return -32757;
  631.                 }
  632.             } else
  633.                 return -32759;
  634.  
  635.             /* match negative records so that they are replaced */
  636.             if (target_rrp->rdlength == 0)
  637.                 return 0;
  638.         }
  639.     }
  640.     /* if a query has gotten this far, match it */
  641.     if (search_rrp->source == RR_QUERY)
  642.         return 0;
  643.  
  644.     /* ensure negative records don't replace older records */
  645.     if (search_rrp->rdlength == 0)
  646.         return -32757;
  647.  
  648.     /* match expired records so that they are replaced */
  649.     if (search_rrp->source != RR_INQUERY) {
  650.         if (target_rrp->ttl == 0L)
  651.             return 0;
  652.     }
  653.     /* Note: rdlengths are not compared because they vary depending
  654.      * on the representation (ASCII or encoded) this record was
  655.      * generated from.
  656.      */
  657.  
  658.     switch (search_rrp->type) {
  659.         case TYPE_A:
  660.             i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  661.             break;
  662.         case TYPE_CNAME:
  663.         case TYPE_MB:
  664.         case TYPE_MG:
  665.         case TYPE_MR:
  666.         case TYPE_NS:
  667.         case TYPE_PTR:
  668.         case TYPE_TXT:
  669.             if (!search_rrp->rdata.data || !target_rrp->rdata.data)
  670.                 i = -32764;
  671.             else
  672.                 i = stricmp (search_rrp->rdata.data, target_rrp->rdata.data);
  673.             break;
  674.         case TYPE_HINFO:
  675.             i = stricmp (search_rrp->rdata.hinfo.cpu, target_rrp->rdata.hinfo.cpu) ||
  676.                 stricmp (search_rrp->rdata.hinfo.os, target_rrp->rdata.hinfo.os);
  677.             break;
  678.         case TYPE_MX:
  679.             i = stricmp (search_rrp->rdata.mx.exch, target_rrp->rdata.mx.exch);
  680.             break;
  681.         case TYPE_SOA:
  682.             i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  683.             break;
  684.         default:
  685.             i = -32755;    /* unsupported */
  686.     }
  687.     return i;
  688. }
  689.  
  690.  
  691.  
  692. static int
  693. compare_rr_list (register struct rr *rrlp, register struct rr *target_rrp)
  694. {
  695.     while (rrlp != NULLRR) {
  696.         if (compare_rr (rrlp, target_rrp) == 0)
  697.             return 0;
  698. #ifdef DEBUG_PAIN
  699.         if (Dtrace)
  700.             tcmdprintf ("%15d %s\n", compare_rr (rrlp, target_rrp), target_rrp->name);
  701. #endif
  702.         rrlp = rrlp->next;
  703.     }
  704.     return -32767;
  705. }
  706.  
  707.  
  708.  
  709. /* Make a new copy of a resource record */
  710. static struct rr *
  711. copy_rr (register struct rr *rrp)
  712. {
  713. register struct rr *newrr;
  714.  
  715.     if (rrp == NULLRR)
  716.         return NULLRR;
  717.  
  718.     newrr = (struct rr *) callocw (1, sizeof (struct rr));
  719.  
  720.     newrr->source = rrp->source;
  721.     newrr->name = strdup (rrp->name);
  722.     newrr->type = rrp->type;
  723.     newrr->class = rrp->class;
  724.     newrr->ttl = rrp->ttl;
  725.     if (rrp->suffix != NULLCHAR)
  726.         newrr->suffix = strdup (rrp->suffix);
  727.     if ((newrr->rdlength = rrp->rdlength) == 0)
  728.         return newrr;
  729.  
  730.     switch (rrp->type) {
  731.         case TYPE_A:
  732.             newrr->rdata.addr = rrp->rdata.addr;
  733.             break;
  734.         case TYPE_CNAME:
  735.         case TYPE_MB:
  736.         case TYPE_MG:
  737.         case TYPE_MR:
  738.         case TYPE_NS:
  739.         case TYPE_PTR:
  740.         case TYPE_TXT:
  741.             newrr->rdata.name = strdup (rrp->rdata.name);
  742.             break;
  743.         case TYPE_HINFO:
  744.             newrr->rdata.hinfo.cpu = strdup (rrp->rdata.hinfo.cpu);
  745.             newrr->rdata.hinfo.os = strdup (rrp->rdata.hinfo.os);
  746.             break;
  747.         case TYPE_MX:
  748.             newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  749.             newrr->rdata.mx.exch = strdup (rrp->rdata.mx.exch);
  750.             break;
  751.         case TYPE_SOA:
  752.             newrr->rdata.soa.mname = strdup (rrp->rdata.soa.mname);
  753.             newrr->rdata.soa.rname = strdup (rrp->rdata.soa.rname);
  754.             newrr->rdata.soa.serial = rrp->rdata.soa.serial;
  755.             newrr->rdata.soa.refresh = rrp->rdata.soa.refresh;
  756.             newrr->rdata.soa.retry = rrp->rdata.soa.retry;
  757.             newrr->rdata.soa.expire = rrp->rdata.soa.expire;
  758.             newrr->rdata.soa.minimum = rrp->rdata.soa.minimum;
  759.             break;
  760.         default:
  761.             break;
  762.     }
  763.     return newrr;
  764. }
  765.  
  766.  
  767.  
  768. static struct rr *
  769. copy_rr_list (register struct rr *rrlp)
  770. {
  771. register struct rr **rrpp;
  772. struct rr *result_rrlp;
  773.  
  774.     rrpp = &result_rrlp;
  775.     while (rrlp != NULLRR) {
  776.         *rrpp = copy_rr (rrlp);
  777.         rrpp = &(*rrpp)->next;
  778.         rrlp = rrlp->next;
  779.     }
  780.     *rrpp = NULLRR;
  781.     return result_rrlp;
  782. }
  783.  
  784.  
  785.  
  786. /* Free (list of) resource records */
  787. void
  788. free_rr (register struct rr *rrlp)
  789. {
  790. register struct rr *rrp;
  791.  
  792.     while ((rrp = rrlp) != NULLRR) {
  793.         rrlp = rrlp->next;
  794.  
  795.         free (rrp->comment);
  796.         free (rrp->suffix);
  797.         free (rrp->name);
  798.         if (rrp->rdlength > 0) {
  799.             switch (rrp->type) {
  800.                 case TYPE_A:
  801.                     break;    /* Nothing allocated in rdata section */
  802.                 case TYPE_CNAME:
  803.                 case TYPE_MB:
  804.                 case TYPE_MG:
  805.                 case TYPE_MR:
  806.                 case TYPE_NS:
  807.                 case TYPE_PTR:
  808.                 case TYPE_TXT:
  809.                     free (rrp->rdata.name);
  810.                     break;
  811.                 case TYPE_HINFO:
  812.                     free (rrp->rdata.hinfo.cpu);
  813.                     free (rrp->rdata.hinfo.os);
  814.                     break;
  815.                 case TYPE_MX:
  816.                     free (rrp->rdata.mx.exch);
  817.                     break;
  818.                 case TYPE_SOA:
  819.                     free (rrp->rdata.soa.mname);
  820.                     free (rrp->rdata.soa.rname);
  821.                     break;
  822.                 default:
  823.                     break;
  824.             }
  825.         }
  826.         free ((char *) rrp);
  827.     }
  828. }
  829.  
  830.  
  831.  
  832. static struct rr *
  833. make_rr (int source, char *dname, int16 dclass, int16 dtype, int32 ttl, int16 rdl, void *data)
  834. {
  835. register struct rr *newrr;
  836.  
  837.     newrr = (struct rr *) callocw (1, sizeof (struct rr));
  838.  
  839.     newrr->source = (char) source;
  840.     newrr->name = strdup (dname);
  841.     newrr->class = dclass;
  842.     newrr->type = dtype;
  843.     newrr->ttl = ttl;
  844.     if ((newrr->rdlength = rdl) == 0)
  845.         return newrr;
  846.  
  847.     switch (dtype) {
  848.         case TYPE_A:
  849.             {
  850.             register uint32 *ap = (uint32 *) data;
  851.  
  852.                 newrr->rdata.addr = *ap;
  853.             }
  854.             break;
  855.         case TYPE_CNAME:
  856.         case TYPE_MB:
  857.         case TYPE_MG:
  858.         case TYPE_MR:
  859.         case TYPE_NS:
  860.         case TYPE_PTR:
  861.         case TYPE_TXT:
  862.             newrr->rdata.name = strdup ((char *) data);
  863.             break;
  864.         case TYPE_HINFO:
  865.             {
  866.             register struct hinfo *hinfop = (struct hinfo *) data;
  867.  
  868.                 newrr->rdata.hinfo.cpu = strdup (hinfop->cpu);
  869.                 newrr->rdata.hinfo.os = strdup (hinfop->os);
  870.             }
  871.             break;
  872.         case TYPE_MX:
  873.             {
  874.             register struct mx *mxp = (struct mx *) data;
  875.  
  876.                 newrr->rdata.mx.pref = mxp->pref;
  877.                 newrr->rdata.mx.exch = strdup (mxp->exch);
  878.             }
  879.             break;
  880.         case TYPE_SOA:
  881.             {
  882.             register struct soa *soap = (struct soa *) data;
  883.  
  884.                 newrr->rdata.soa.mname = strdup (soap->mname);
  885.                 newrr->rdata.soa.rname = strdup (soap->rname);
  886.                 newrr->rdata.soa.serial = soap->serial;
  887.                 newrr->rdata.soa.refresh = soap->refresh;
  888.                 newrr->rdata.soa.retry = soap->retry;
  889.                 newrr->rdata.soa.expire = soap->expire;
  890.                 newrr->rdata.soa.minimum = soap->minimum;
  891.             }
  892.             break;
  893.         default:
  894.             break;
  895.     }
  896.     return newrr;
  897. }
  898.  
  899.  
  900.  
  901. /**
  902.  **     Domain Cache Utilities
  903.  **/
  904.  
  905. static void
  906. dcache_add (register struct rr *rrlp)
  907. {
  908. register struct rr *last_rrp;
  909. struct rr *save_rrp;
  910.  
  911.     if (rrlp == NULLRR)
  912.         return;
  913.  
  914.     save_rrp = rrlp;
  915.     last_rrp = NULLRR;
  916.     while (rrlp != NULLRR) {
  917.         rrlp->last = last_rrp;
  918.         last_rrp = rrlp;
  919.         rrlp = rrlp->next;
  920.     }
  921.     if (last_rrp != NULLRR)    {
  922.         last_rrp->next = Dcache;
  923.         if (Dcache != NULLRR)
  924.             Dcache->last = last_rrp;
  925.         Dcache = save_rrp;
  926.     }
  927. }
  928.  
  929.  
  930.  
  931. static void
  932. dcache_drop (register struct rr *rrp)
  933. {
  934.     if (rrp->last != NULLRR)
  935.         rrp->last->next = rrp->next;
  936.     else
  937.         Dcache = rrp->next;
  938.     if (rrp->next != NULLRR)
  939.         rrp->next->last = rrp->last;
  940.     rrp->last =
  941.         rrp->next = NULLRR;
  942. }
  943.  
  944.  
  945.  
  946. /* Search cache for resource records, removing them from the cache.
  947.  * Also, timeout cache entries, and trim cache to size.
  948.  * (Calling with NULLRR is legal -- will timeout & trim only.)
  949.  * Note that an answer from the cache cannot be authoritative, because
  950.  * we cannot guarantee that all the entries remain from a previous request.
  951.  * Returns RR list, or NULLRR if no record found.
  952.  */
  953. static struct rr *
  954. dcache_search (struct rr *rrlp)
  955. {
  956. register struct rr *rrp, *test_rrp;
  957. struct rr **rrpp, *result_rrlp;
  958. int32 elapsed;
  959. time_t now;
  960. int count = 0;
  961.  
  962. #ifdef DEBUG
  963.     if (Dtrace && rrlp != NULLRR)
  964.         tcmdprintf ("dcache_search: searching for %s\n", rrlp->name);
  965. #endif
  966.  
  967.     elapsed = (int32) (time (&now) - Dcache_time);
  968.     Dcache_time = now;
  969.  
  970.     rrpp = &result_rrlp;
  971.     for (rrp = Dcache; (test_rrp = rrp) != NULLRR;) {
  972.         rrp = rrp->next;
  973.         /* timeout entries */
  974.         if (test_rrp->ttl > 0L
  975.             && (test_rrp->ttl -= elapsed) <= 0L)
  976.             test_rrp->ttl = 0L;
  977.  
  978.         if (compare_rr_list (rrlp, test_rrp) == 0) {
  979.             dcache_drop (*rrpp = test_rrp);
  980.             rrpp = &(*rrpp)->next;
  981.         } else if (test_rrp->source == RR_FILE && ++count > Dcache_size) {
  982.             dcache_drop (test_rrp);
  983.             free_rr (test_rrp);
  984.         }
  985.     }
  986.     *rrpp = NULLRR;
  987.     return result_rrlp;
  988. }
  989.  
  990.  
  991.  
  992. /* Move a list of resource records to the cache, removing duplicates. */
  993. static void
  994. dcache_update (register struct rr *rrlp)
  995. {
  996.     if (rrlp == NULLRR)
  997.         return;
  998.  
  999.     free_rr (dcache_search (rrlp));    /* remove duplicates, first */
  1000.     dcache_add (rrlp);
  1001. }
  1002.  
  1003.  
  1004.  
  1005. /**
  1006.  **     File Utilities
  1007.  **/
  1008.  
  1009. static struct rr *
  1010. get_rr (FILE *fp, struct rr *lastrrp)
  1011. {
  1012. char *line, *lp;
  1013. struct rr *rrp;
  1014. char *ttl, *class, *type, *data = NULLCHAR;
  1015. char const *name;
  1016. int i;
  1017.  
  1018. corrupted:
  1019.     line = getline (fp);
  1020.     if (line == NULLCHAR)    /* eof or error */
  1021.         return NULLRR;
  1022.  
  1023.     rrp = (struct rr *) callocw (1, sizeof (struct rr));
  1024.  
  1025.     rrp->source = RR_FILE;
  1026.  
  1027.     if (line[0] == '$') {
  1028.         data = strtok (line, delim);
  1029.         if (strnicmp (data, "$origin", 7) == 0) {
  1030.             data = strtok (NULLCHAR, delim);
  1031.             if (data != NULLCHAR)
  1032.                 rrp->suffix = strdup (data);
  1033.             else {    /* this is a corrupted domain.txt file */
  1034.                 log (-1, "The domain.txt file seems corrupted! Check for '$origin' lines");
  1035.                 goto corrupted;
  1036.             }
  1037.             line[strlen (line)] = ' ';
  1038.             rrp->comment = strdup (line);
  1039.             rrp->type = TYPE_MISSING;
  1040.             free (line);
  1041.             return rrp;
  1042.         }
  1043.         if (strnicmp (data, "$include", 8) == 0) {
  1044.             data = strtok (NULLCHAR, delim);
  1045.             if (data != NULLCHAR)
  1046.                 rrp->suffix = strdup (data);
  1047.             else {    /* this is a corrupted domain.txt file */
  1048.                 log (-1, "The domain.txt file seems corrupted! Check for '$include' lines");
  1049.                 goto corrupted;
  1050.             }
  1051.             line[strlen (line)] = ' ';
  1052.             rrp->comment = strdup (line);
  1053.             rrp->type = TYPE_INCLUDE;
  1054.             free (line);
  1055.             return rrp;
  1056.         }
  1057.     } else {
  1058.         if (lastrrp != NULLRR)
  1059.             if (lastrrp->suffix != NULLCHAR)
  1060.                 rrp->suffix = strdup (lastrrp->suffix);
  1061.     }
  1062.  
  1063.     if (!isspace (line[0]) || lastrrp == NULLRR) {
  1064.         name = strtok (line, delim);
  1065.         lp = NULLCHAR;
  1066.     } else {        /* Name field is missing */
  1067.         name = lastrrp->name;
  1068.         lp = line;
  1069.     }
  1070.  
  1071.     if (name != NULLCHAR && name[0] == '@') {
  1072.         if (rrp->suffix != NULLCHAR)
  1073.             name = rrp->suffix;
  1074.         else {
  1075.             if (Dsuffix != NULLCHAR)
  1076.                 name = Dsuffix;
  1077.             else
  1078.                 name = "ampr.org.";
  1079.         }
  1080.     }
  1081.     /* make the rrp->suffix the Dsuffix, if it is defined */
  1082.     if (Dsuffix != NULLCHAR && rrp->suffix == NULLCHAR)
  1083.         rrp->suffix = strdup (Dsuffix);
  1084.  
  1085.     if (name == NULLCHAR)    {
  1086.         log (-1, "The domain.txt file seems corrupted! Check for lines with missing hostnames");
  1087.         goto corrupted;
  1088.     }
  1089.     i = (int) strlen (name);
  1090.     if (name[i - 1] != '.') {
  1091.         /* Tack on the current domain suffix if defined */
  1092.         if (rrp->suffix != NULLCHAR) {
  1093.             rrp->name = mallocw ((int16) i + strlen (rrp->suffix) + 2);
  1094.             sprintf (rrp->name, "%s.%s", name, rrp->suffix);
  1095.         } else {
  1096.             /* Tack on a trailing period if it's not there */
  1097.             rrp->name = mallocw ((unsigned) i + 2);
  1098.             strcpy (rrp->name, name);
  1099.             strcat (rrp->name, ".");
  1100.         }
  1101.     } else
  1102.         /* fully qualified domain name */
  1103.         rrp->name = strdup (name);
  1104.  
  1105.     ttl = strtok (lp, delim);
  1106.  
  1107.     if (ttl == NULLCHAR || (!isdigit (ttl[0]) && ttl[0] != '-')) {
  1108.         /* Optional ttl field is missing */
  1109.         rrp->ttl = (long) TTL_MISSING;
  1110.         class = ttl;
  1111.     } else {
  1112.         rrp->ttl = atol (ttl);
  1113.         class = strtok (NULLCHAR, delim);
  1114.     }
  1115.  
  1116.     if (class == NULLCHAR) {
  1117.         /* we're in trouble, but keep processing */
  1118.         rrp->class = CLASS_MISSING;
  1119.         type = class;
  1120.     } else if (class[0] == '<') {
  1121.         rrp->class = (int16) atoi (&class[1]);
  1122.         type = strtok (NULLCHAR, delim);
  1123.     } else if (stricmp (class, "IN") == 0) {
  1124.         rrp->class = CLASS_IN;
  1125.         type = strtok (NULLCHAR, delim);
  1126.     } else {
  1127.         /* Optional class field is missing; assume IN */
  1128.         rrp->class = CLASS_IN;
  1129.         type = class;
  1130.     }
  1131.  
  1132.     if (type == NULLCHAR) {
  1133.         /* we're in trouble, but keep processing */
  1134.         rrp->type = TYPE_MISSING;
  1135.         data = type;
  1136.     } else if (type[0] == '{') {
  1137.         rrp->type = (int16) atoi (&class[1]);    /*lint !e613 */
  1138.         data = strtok (NULLCHAR, delim);
  1139.     } else {
  1140.         rrp->type = TYPE_MISSING;
  1141.         for (i = 1; i < NDTYPES; i++) {
  1142.             if (stricmp (type, Dtypes[i]) == 0) {
  1143.                 rrp->type = (int16) i;
  1144.                 data = strtok (NULLCHAR, delim);
  1145.                 break;
  1146.             }
  1147.         }
  1148.     }
  1149.  
  1150.     if (rrp->type == TYPE_MISSING)
  1151.         data = NULLCHAR;
  1152.  
  1153.     if (data == NULLCHAR) {
  1154.         /* Empty record, just return */
  1155.         free (line);
  1156.         return rrp;
  1157.     }
  1158.     switch (rrp->type) {
  1159.         case TYPE_A:
  1160.             rrp->rdlength = 4;
  1161.             rrp->rdata.addr = aton (data);
  1162.             break;
  1163.         case TYPE_CNAME:
  1164.             i = (int) strlen (data);
  1165.             if (data[i - 1] != '.') {    /* not fully qualified */
  1166.                 if (rrp->suffix != NULLCHAR) {
  1167.                     rrp->rdata.name = mallocw ((int16)i + strlen (rrp->suffix) + 2);
  1168.                     sprintf (rrp->rdata.name, "%s.%s", data, rrp->suffix);
  1169.                 } else {
  1170.                     rrp->rdata.name = mallocw ((int16) i + 2);
  1171.                     strcpy (rrp->rdata.name, data);
  1172.                     strcat (rrp->rdata.name, ".");
  1173.                 }
  1174.             } else
  1175.                 rrp->rdata.name = strdup (data);
  1176.             rrp->rdlength = (int16) strlen (rrp->rdata.name);
  1177.             break;
  1178.         case TYPE_MB:
  1179.         case TYPE_MG:
  1180.         case TYPE_MR:
  1181.         case TYPE_NS:
  1182.         case TYPE_PTR:
  1183.         case TYPE_TXT:
  1184.             rrp->rdlength = (int16) strlen (data);
  1185.             rrp->rdata.name = strdup (data);
  1186.             break;
  1187.         case TYPE_HINFO:
  1188.             rrp->rdlength = (int16) strlen (data);
  1189.             rrp->rdata.hinfo.cpu = strdup (data);
  1190.             if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
  1191.                 rrp->rdlength += (int16) strlen (data);
  1192.                 rrp->rdata.hinfo.os = strdup (data);
  1193.             }
  1194.             break;
  1195.         case TYPE_MX:
  1196.             rrp->rdata.mx.pref = (int16) atoi (data);
  1197.             rrp->rdlength = 2;
  1198.  
  1199.             /* Get domain name of exchanger */
  1200.             if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
  1201.                 rrp->rdlength += (int16) strlen (data);
  1202.                 rrp->rdata.mx.exch = strdup (data);
  1203.             }
  1204.             break;
  1205.         case TYPE_SOA:
  1206.             /* Get domain name of master name server */
  1207.             rrp->rdlength = (int16) strlen (data);
  1208.             rrp->rdata.soa.mname = strdup (data);
  1209.  
  1210.             /* Get domain name of irresponsible person */
  1211.             if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
  1212.                 rrp->rdata.soa.rname = strdup (data);
  1213.                 rrp->rdlength += (int16) strlen (data);
  1214.             }
  1215.  
  1216.             {
  1217.                 int corrupt = 0;
  1218.  
  1219.                 if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
  1220.                     rrp->rdata.soa.serial = atol (data);
  1221.                 else
  1222.                     corrupt = 1;
  1223.                 if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
  1224.                     rrp->rdata.soa.refresh = atol (data);
  1225.                 else
  1226.                     corrupt = 1;
  1227.                 if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
  1228.                     rrp->rdata.soa.retry = atol (data);
  1229.                 else
  1230.                     corrupt = 1;
  1231.                 if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
  1232.                     rrp->rdata.soa.expire = atol (data);
  1233.                 else
  1234.                     corrupt = 1;
  1235.                 if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
  1236.                     rrp->rdata.soa.minimum = atol (data);
  1237.                 else
  1238.                     corrupt = 1;
  1239.                 if (corrupt) {    /* this is a corrupted domain.txt file */
  1240.                     log (-1, "The domain.txt file seems corrupted! Check for '$soa' lines");
  1241.                     goto corrupted;
  1242.                 }
  1243.             }
  1244.             rrp->rdlength += 20;
  1245.             break;
  1246.         default:
  1247.             break;
  1248.     }
  1249.  
  1250.     /* !!! need to handle trailing comments */
  1251.     free (line);
  1252.     return rrp;
  1253. }
  1254.  
  1255.  
  1256.  
  1257. /* Print a resource record */
  1258. static void
  1259. put_rr (FILE *fp, struct rr *rrp)
  1260. {
  1261. int trans;
  1262. int trace = 0;
  1263.  
  1264.     if (fp == NULLFILE || rrp == NULLRR)
  1265.         return;
  1266.  
  1267.     if (fp == stdout)
  1268.         trace = 1;
  1269.  
  1270.     if (rrp->name == NULLCHAR && rrp->comment != NULLCHAR) {
  1271.         if (trace)
  1272.             tcmdprintf ("%s\n", rrp->comment);
  1273.         else
  1274.             fprintf (fp, "%s\n", rrp->comment);
  1275.         return;
  1276.     }
  1277.     if (trace)
  1278.         tcmdprintf ("%s", rrp->name);
  1279.     else
  1280.         fprintf (fp, "%s", rrp->name);
  1281.     if (rrp->ttl != (int32) TTL_MISSING) {
  1282.         if (trace)
  1283.             tcmdprintf ("\t%ld", rrp->ttl);
  1284.         else
  1285.             fprintf (fp, "\t%ld", rrp->ttl);
  1286.     }
  1287.     if (rrp->class == CLASS_IN) {
  1288.         if (trace)
  1289.             tcmdprintf ("\tIN");
  1290.         else
  1291.             fprintf (fp, "\tIN");
  1292.     } else {
  1293.         if (trace)
  1294.             tcmdprintf ("\t<%u>", rrp->class);
  1295.         else
  1296.             fprintf (fp, "\t<%u>", rrp->class);
  1297.     }
  1298.     if (rrp->type < NDTYPES) {
  1299.         if (trace)
  1300.             tcmdprintf ("\t%s", Dtypes[rrp->type]);
  1301.         else
  1302.             fprintf (fp, "\t%s", Dtypes[rrp->type]);
  1303.     } else {
  1304.         if (trace)
  1305.             tcmdprintf ("\t{%u}", rrp->type);
  1306.         else
  1307.             fprintf (fp, "\t{%u}", rrp->type);
  1308.     }
  1309.     if (rrp->rdlength == 0) {
  1310.         /* Null data portion, indicates nonexistent record */
  1311.         /* or unsupported type.  Hopefully, these will filter */
  1312.         /* as time goes by. */
  1313.         if (trace)
  1314.             tcmdprintf ("\n");
  1315.         else
  1316.             fprintf (fp, "\n");
  1317.         return;
  1318.     }
  1319.     switch (rrp->type) {
  1320.         case TYPE_A:
  1321.             trans = DTranslate;    /* Save IP address translation state */
  1322.             DTranslate = 0;    /* Force output to be numeric IP addr */
  1323.             if (trace)
  1324.                 tcmdprintf ("\t%s\n", inet_ntoa (rrp->rdata.addr));
  1325.             else
  1326.                 fprintf (fp, "\t%s\n", inet_ntoa (rrp->rdata.addr));
  1327.             DTranslate = trans;    /* Restore original state */
  1328.             break;
  1329.         case TYPE_CNAME:
  1330.         case TYPE_MB:
  1331.         case TYPE_MG:
  1332.         case TYPE_MR:
  1333.         case TYPE_NS:
  1334.         case TYPE_PTR:
  1335.         case TYPE_TXT:
  1336.             /* These are all printable text strings */
  1337.             if (trace)
  1338.                 tcmdprintf ("\t%s\n", rrp->rdata.data);
  1339.             else
  1340.                 fprintf (fp, "\t%s\n", rrp->rdata.data);
  1341.             break;
  1342.         case TYPE_HINFO:
  1343.             if (trace)
  1344.                 tcmdprintf ("\t%s\t%s\n", rrp->rdata.hinfo.cpu, rrp->rdata.hinfo.os);
  1345.             else
  1346.                 fprintf (fp, "\t%s\t%s\n", rrp->rdata.hinfo.cpu, rrp->rdata.hinfo.os);
  1347.             break;
  1348.         case TYPE_MX:
  1349.             if (trace)
  1350.                 tcmdprintf ("\t%u\t%s\n", rrp->rdata.mx.pref, rrp->rdata.mx.exch);
  1351.             else
  1352.                 fprintf (fp, "\t%u\t%s\n", rrp->rdata.mx.pref, rrp->rdata.mx.exch);
  1353.             break;
  1354.         case TYPE_SOA:
  1355.             if (trace)
  1356.                 tcmdprintf ("\t%s\t%s\n\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1357.                     rrp->rdata.soa.mname, rrp->rdata.soa.rname,
  1358.                     rrp->rdata.soa.serial, rrp->rdata.soa.refresh,
  1359.                     rrp->rdata.soa.retry, rrp->rdata.soa.expire,
  1360.                     rrp->rdata.soa.minimum);
  1361.             else
  1362.                 fprintf (fp, "\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1363.                     rrp->rdata.soa.mname, rrp->rdata.soa.rname,
  1364.                     rrp->rdata.soa.serial, rrp->rdata.soa.refresh,
  1365.                     rrp->rdata.soa.retry, rrp->rdata.soa.expire,
  1366.                     rrp->rdata.soa.minimum);
  1367.             break;
  1368.         default:
  1369.             if (trace)
  1370.                 tcmdprintf ("\n");
  1371.             else
  1372.                 fprintf (fp, "\n");
  1373.             break;
  1374.     }
  1375.     }
  1376.  
  1377.  
  1378.  
  1379. static struct rr *
  1380. dfile_search_file (struct rr *rrlp, const char *filename)
  1381. {
  1382. register struct rr *frrp;
  1383. struct rr **rrpp, *result_rrlp, *oldrrp, *recurse_rrlp;
  1384. int32 elapsed;
  1385. FILE *dbase;
  1386. struct stat dstat;
  1387.  
  1388.     if ((dbase = fopen (filename, READ_TEXT)) == NULLFILE)
  1389.         return NULLRR;
  1390.  
  1391.     if (fstat (fileno (dbase), &dstat) != 0) {
  1392.         tputs ("Dfile_Search: can't get file status\n");
  1393.         (void) fclose (dbase);
  1394.         return NULLRR;
  1395.     }
  1396.     if ((elapsed = (int32) (Dcache_time - (time_t) dstat.st_ctime)) < 0L)
  1397.         elapsed = -elapsed;    /* arbitrary time mismatch */
  1398.  
  1399.     result_rrlp = NULLRR;    /* for contiguous test below */
  1400.     oldrrp = NULLRR;
  1401.     rrpp = &result_rrlp;
  1402.     while ((frrp = get_rr (dbase, oldrrp)) != NULLRR) {
  1403.         if (frrp->type == TYPE_INCLUDE) {
  1404.             /* frrp->suffix contains the filename, and
  1405.                frrp->comment contains the entire line */
  1406.             recurse_rrlp = dfile_search_file (rrlp, frrp->suffix);
  1407.             free_rr (frrp);
  1408.             frrp = recurse_rrlp;
  1409.             if (frrp == NULLRR)
  1410.                 continue;
  1411.         }
  1412.         free_rr (oldrrp);
  1413.         if (frrp->type != TYPE_MISSING && frrp->rdlength > 0 && compare_rr_list (rrlp, frrp) == 0) {
  1414.             if (frrp->ttl > 0L && (frrp->ttl -= elapsed) <= 0L)
  1415.                 frrp->ttl = 0L;
  1416.             *rrpp = frrp;
  1417.             rrpp = &(*rrpp)->next;
  1418.             oldrrp = copy_rr (frrp);
  1419.         } else {
  1420.             oldrrp = frrp;
  1421.             /*    All records of the same name and the same type
  1422.                 are contiguous.  Therefore, for a single query,
  1423.                 we can stop searching.  Multiple queries must
  1424.                 read the whole file.
  1425.             */
  1426.             if (rrlp->next == NULLRR && result_rrlp != NULLRR)
  1427.                 break;
  1428.         }
  1429.         if (!main_exit && Mprunning)
  1430.             kwait (NULL);    /* run multiple sessions */
  1431.     }
  1432.     free_rr (oldrrp);
  1433.     *rrpp = NULLRR;
  1434.  
  1435.     (void) fclose (dbase);
  1436.     return result_rrlp;
  1437. }
  1438.  
  1439.  
  1440.  
  1441. /* Search local database for resource records.
  1442.  * Returns RR list, or NULLRR if no record found.
  1443.  */
  1444. static struct rr *
  1445. dfile_search (struct rr *rrlp)
  1446. {
  1447. struct rr *result_rrlp;
  1448.  
  1449. #ifdef DEBUG
  1450.     if (Dtrace)
  1451.         tcmdprintf ("Dfile_Search: Searching for \"%s\"\n", rrlp->name);
  1452. #endif
  1453.  
  1454.     while (Dfile_writing > 0)
  1455.         kwait (&Dfile_reading);
  1456.     Dfile_reading++;
  1457.  
  1458.     result_rrlp = dfile_search_file (rrlp, DomainFile);
  1459.  
  1460.     if (--Dfile_reading <= 0) {
  1461.         Dfile_reading = 0;
  1462.         ksignal (&Dfile_writing, 0);
  1463.     }
  1464.     return result_rrlp;
  1465. }
  1466.  
  1467.  
  1468.  
  1469. /* Process which will add new resource records from the cache
  1470.  * to the local file, eliminating duplicates while it goes.
  1471.  */
  1472. static void
  1473. dfile_update (int s OPTIONAL, void *unused OPTIONAL, void *p OPTIONAL)
  1474. {
  1475. struct rr **rrpp, *rrlp, *oldrrp;
  1476. char *newname;
  1477. FILE *old_fp, *new_fp;
  1478. struct stat old_stat, new_stat;
  1479.  
  1480.     log (-1, "update DOMAIN.TXT initiated");
  1481.  
  1482.     close_s (Curproc->input);
  1483.     Curproc->input = -1;
  1484.     close_s (Curproc->output);
  1485.     Curproc->output = -1;
  1486.  
  1487.     newname = strdup (DomainFile);
  1488.     strcpy (&newname[strlen (newname) - 3], "tmp");
  1489.  
  1490.     while (Dfile_wait_absolute != 0L && !main_exit) {
  1491.         register struct rr *frrp;
  1492.         int32 elapsed;
  1493.  
  1494.         while (Dfile_wait_absolute != 0L) {
  1495.             elapsed = Dfile_wait_absolute - secclock ();
  1496.             Dfile_wait_absolute = 0L;
  1497.             if (elapsed > 0L && !main_exit) {
  1498.                 kalarm (elapsed * 1000L);
  1499.                 kwait (&Dfile_wait_absolute);
  1500.                 kalarm (0L);
  1501.             }
  1502.         }
  1503.  
  1504.         log (-1, "update DOMAIN.TXT");
  1505.  
  1506.         /* create new file for copy */
  1507.         if ((new_fp = fopen (newname, WRITE_TEXT)) == NULLFILE) {
  1508.             printf ("Dfile_Update: can't create \"%s\"!\n", newname);
  1509.             break;
  1510.         }
  1511.         if (fstat (fileno (new_fp), &new_stat) != 0) {
  1512.             printf ("Dfile_Update: can't get new_file status!\n");
  1513.             (void) fclose (new_fp);
  1514.             break;
  1515.         }
  1516.         kwait (NULL);    /* file operations can be slow */
  1517.  
  1518.         /* timeout the cache one last time before writing */
  1519.         (void) dcache_search (NULLRR);
  1520.  
  1521.         /* copy new RRs out to the new file */
  1522.         /* (can't wait here, the cache might change) */
  1523.         rrpp = &rrlp;
  1524.         for (frrp = Dcache; frrp != NULLRR; frrp = frrp->next) {
  1525.             switch (frrp->source) {
  1526.                 case RR_QUESTION:
  1527.                 case RR_ANSWER:
  1528.                 case RR_AUTHORITY:
  1529.                 case RR_ADDITIONAL:
  1530.                     *rrpp = copy_rr (frrp);
  1531.                     if (frrp->type != TYPE_MISSING
  1532.                         && frrp->rdlength > 0)
  1533.                         put_rr (new_fp, frrp);
  1534.                     rrpp = &(*rrpp)->next;
  1535.                     frrp->source = RR_FILE;
  1536.                     break;
  1537.                 default:
  1538.                     break;
  1539.             }
  1540.         }
  1541.         *rrpp = NULLRR;
  1542.  
  1543.         /* open up the old file, concurrently with everyone else */
  1544.         if ((old_fp = fopen (DomainFile, READ_TEXT)) == NULLFILE) {
  1545.             /* great! no old file, so we're ready to go. */
  1546.             (void) fclose (new_fp);
  1547.             (void) rename (newname, DomainFile);
  1548.             free_rr (rrlp);
  1549.             break;
  1550.         }
  1551.         if (fstat (fileno (old_fp), &old_stat) != 0) {
  1552.             printf ("Dfile_Update: can't get old_file status!\n");
  1553.             (void) fclose (new_fp);
  1554.             (void) fclose (old_fp);
  1555.             free_rr (rrlp);
  1556.             break;
  1557.         }
  1558.         if ((elapsed = (int32) (new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1559.             elapsed = -elapsed;    /* file times are inconsistant */
  1560.  
  1561.         /* Now append any non-duplicate records */
  1562.         oldrrp = NULLRR;
  1563.         while ((frrp = get_rr (old_fp, oldrrp)) != NULLRR) {
  1564.             free_rr (oldrrp);
  1565.             if (frrp->name == NULLCHAR
  1566.                 && frrp->comment != NULLCHAR)
  1567.                 put_rr (new_fp, frrp);
  1568.             if (frrp->type == TYPE_INCLUDE)
  1569.                 frrp->type = TYPE_MISSING;
  1570.             if (frrp->type != TYPE_MISSING && frrp->rdlength > 0 && compare_rr_list (rrlp, frrp) != 0) {
  1571.                 if (frrp->ttl > 0L && (frrp->ttl -= elapsed) <= 0L)
  1572.                     frrp->ttl = 0L;
  1573.                 if (frrp->ttl != 0 || !Dfile_clean)
  1574.                     put_rr (new_fp, frrp);
  1575.             }
  1576.             oldrrp = frrp;
  1577.             if (!main_exit)
  1578.                 kwait (NULL);    /* run in background */
  1579.         }
  1580.         free_rr (oldrrp);
  1581.         (void) fclose (new_fp);
  1582.         (void) fclose (old_fp);
  1583.         free_rr (rrlp);
  1584.  
  1585.         /* wait for everyone else to finish reading */
  1586.         Dfile_writing++;
  1587.         while (Dfile_reading > 0)
  1588.             kwait (&Dfile_writing);
  1589.  
  1590.         unlink (DomainFile);
  1591.         (void) rename (newname, DomainFile);
  1592.  
  1593.         Dfile_writing = 0;
  1594.         ksignal (&Dfile_reading, 0);
  1595.     }
  1596.     free (newname);
  1597.  
  1598.     log (-1, "update DOMAIN.TXT finished");
  1599.     Dfile_updater = NULLPROC;
  1600. }
  1601.  
  1602.  
  1603.  
  1604. /**
  1605.  **     Domain Server Utilities
  1606.  **/
  1607.  
  1608. static void
  1609. dumpdomain (struct dhdr *dhp, int32 rtt)
  1610. {
  1611. struct rr *rrp;
  1612.  
  1613.     tcmdprintf ("response id %u (rtt %lu ms) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  1614.         dhp->id, rtt, dhp->qr, dhp->opcode, dhp->aa, dhp->tc, dhp->rd,
  1615.         dhp->ra, dhp->rcode);
  1616.     tcmdprintf ("%u questions:\n", dhp->qdcount);
  1617.     for (rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1618.         tcmdprintf ("%s type %s class %u\n", rrp->name, Dtypes[rrp->type], rrp->class);
  1619.     tcmdprintf ("%u answers:\n", dhp->ancount);
  1620.     for (rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next)
  1621.         put_rr (stdout, rrp);
  1622.     tcmdprintf ("%u authority:\n", dhp->nscount);
  1623.     for (rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next)
  1624.         put_rr (stdout, rrp);
  1625.     tcmdprintf ("%u additional:\n", dhp->arcount);
  1626.     for (rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next)
  1627.         put_rr (stdout, rrp);
  1628. #ifndef UNIX
  1629.     (void) fflush (stdout);
  1630. #endif
  1631. }
  1632.  
  1633.  
  1634.  
  1635. static int
  1636. dns_makequery (op, srrp, buffer, buflen)
  1637. int16 op;            /* operation */
  1638. struct rr *srrp;        /* Search RR */
  1639. char *buffer;            /* Area for query */
  1640. int16 buflen OPTIONAL;        /* Length of same */
  1641. {
  1642. unsigned char *cp;
  1643. char *cp1;
  1644. char *dname, *sname;
  1645. int16 parameter;
  1646. int16 dlen, len;
  1647.  
  1648.     cp = (unsigned char *) buffer;
  1649.     /* Use millisecond clock for timestamping */
  1650.     cp = put16 (cp, (int16) msclock ());
  1651.     parameter = (int16) ((op << 11) | 0x0100);    /* Recursion desired */
  1652.     cp = put16 (cp, parameter);
  1653.     cp = put16 (cp, 1);
  1654.     cp = put16 (cp, 0);
  1655.     cp = put16 (cp, 0);
  1656.     cp = put16 (cp, 0);
  1657.  
  1658.     sname = strdup (srrp->name);
  1659.     dname = sname;
  1660.     dlen = (int16) strlen (dname);
  1661.     for (;;) {
  1662.         /* Look for next dot */
  1663.         cp1 = strchr (dname, '.');
  1664.         if (cp1 != NULLCHAR)
  1665.             len = (int16) (cp1 - dname);    /* More to come */
  1666.         else
  1667.             len = dlen;    /* Last component */
  1668.         *cp++ = uchar(len);    /* Write length of component */
  1669.         if (len == 0)
  1670.             break;
  1671.         /* Copy component up to (but not including) dot */
  1672.         strncpy ((char *) cp, dname, len);
  1673.         cp += len;
  1674.         if (cp1 == NULLCHAR) {
  1675.             *cp++ = 0;    /* Last one; write null and finish */
  1676.             break;
  1677.         }
  1678.         dname += len + 1;
  1679.         dlen -= len + 1;
  1680.     }
  1681.     free (sname);
  1682.     cp = put16 (cp, srrp->type);
  1683.     cp = put16 (cp, srrp->class);
  1684.     return (char *)cp - buffer;
  1685. }
  1686.  
  1687.  
  1688.  
  1689. /* Domain server resolution loop
  1690.  * Returns: Any answers in cache
  1691.  * Future features - multiple queries and inverse queries */
  1692. static void
  1693. dns_query (struct rr *rrlp)
  1694. {
  1695. struct mbuf *bp;
  1696. struct dhdr *dhp;
  1697. struct dserver *dp;    /* server list */
  1698. int32 rtt, abserr;
  1699. int tried = 0;        /* server list has been retried (count) */
  1700.  
  1701.     if (((dp = Dservers) == NULLDOM) || !Mprunning)    {
  1702.         if (!Mprunning)
  1703.             Mprunning_err = 1;
  1704.         return;
  1705.     }
  1706.  
  1707.     for (;;) {
  1708.         char *buf;
  1709.         int len;
  1710.         struct sockaddr_in server_in;
  1711.         int s;
  1712.         int rval;
  1713.  
  1714.         dp->queries++;
  1715.  
  1716.         s = socket (AF_INET, SOCK_DGRAM, 0);
  1717.         server_in.sin_family = AF_INET;
  1718.         server_in.sin_port = IPPORT_DOMAIN;
  1719.         server_in.sin_addr.s_addr = dp->address;
  1720.  
  1721.         if (Dtrace) {
  1722. #if 0
  1723.             /* Make sure this only goes to the command screen
  1724.              * - K2MF */
  1725.             if (Current->output == Command->output)
  1726. #endif
  1727.                 tcmdprintf ("DNS_Query: Querying server (%s) for \"%s\"\n",
  1728.                        inet_ntoa (dp->address), rrlp->name);
  1729.         }
  1730.         buf = mallocw (512);
  1731.         len = dns_makequery (0, rrlp, buf, 512);
  1732.         (void) sendto (s, buf, len, 0, (char *) &server_in, sizeof (server_in));
  1733.         free (buf);
  1734.         kalarm (max (dp->timeout, 100));
  1735.         /* Wait for something to happen */
  1736.         rval = recv_mbuf (s, &bp, 0, NULLCHAR, 0);
  1737.         kalarm (0L);
  1738.         close_s (s);
  1739.  
  1740.         if (Dtrace) {
  1741. #if 0
  1742.             /* Make sure this only goes to the command screen
  1743.              * - K2MF */
  1744.             if (Current->output == Command->output)
  1745. #endif
  1746.                 tcmdprintf ("DNS_Query: Received message length %d, errno %d\n", rval, errno);
  1747.         }
  1748.         if (rval > 0)
  1749.             break;
  1750.  
  1751.         if (errno == EABORT)
  1752.             return;    /* Killed by "reset" command */
  1753.  
  1754.         /* Timeout; back off this one and try another server */
  1755.         dp->timeouts++;
  1756.         dp->timeout <<= 1;        /*lint !e703 */
  1757.  
  1758.         /* But we must have some sort of sensible limit - surely? */
  1759.         if (dp->timeout > (Dserver_maxwait * 1000L))
  1760.             dp->timeout = Dserver_maxwait * 1000L;
  1761.  
  1762.         if ((dp = dp->next) == NULLDOM) {
  1763.             dp = Dservers;
  1764.             if (Dserver_retries > 0 && ++tried > Dserver_retries)
  1765.                 return;
  1766.         }
  1767.     }
  1768.  
  1769.     /* got a response */
  1770.     dp->responses++;
  1771.     dhp = (struct dhdr *) mallocw (sizeof (struct dhdr));
  1772.  
  1773.     (void) ntohdomain (dhp, &bp);    /* Convert to local format */
  1774.  
  1775.     /* Compute and update the round trip time */
  1776.     rtt = (int32) ((int16) msclock () - dhp->id);
  1777.     abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1778.     dp->srtt = ((AGAIN - 1) * dp->srtt + rtt + (AGAIN / 2)) >> LAGAIN;    /*lint !e704 */
  1779.     dp->mdev = ((DGAIN - 1) * dp->mdev + abserr + (DGAIN / 2)) >> LDGAIN;    /*lint !e704 */
  1780.     dp->timeout = 4 * dp->mdev + dp->srtt;
  1781.  
  1782.     /* move to top of list for next time */
  1783.     if (dp->prev != NULLDOM) {
  1784.         dlist_drop (dp);
  1785.         dlist_add (dp);
  1786.     }
  1787.     if (Dtrace) {
  1788. #if 0
  1789.         /* Make sure this only goes to the command screen - K2MF */
  1790.         if (Current->output == Command->output)
  1791. #endif
  1792.             dumpdomain (dhp, rtt);
  1793.     }
  1794.     /* Add negative reply to answers.  This assumes that there was
  1795.      * only one question, which is true for all questions we send.
  1796.      */
  1797.     if (dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)) {
  1798.         register struct rr *rrp;
  1799.         long ttl = 600L;/* Default TTL for negative records */
  1800.  
  1801.         /* look for SOA ttl */
  1802.         for (rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next) {
  1803.             if (rrp->type == TYPE_SOA)
  1804.                 ttl = rrp->ttl;
  1805.         }
  1806.  
  1807.         /* make the questions the negative answers */
  1808.         for (rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1809.             rrp->ttl = ttl;
  1810.     } else {
  1811.         free_rr (dhp->questions);
  1812.         dhp->questions = NULLRR;
  1813.     }
  1814.  
  1815.     /* post in reverse order to maintain original order */
  1816.     dcache_update (dhp->additional);
  1817.     dcache_update (dhp->authority);
  1818.     dcache_update (dhp->answers);
  1819.     dcache_update (dhp->questions);
  1820.  
  1821.     Dfile_wait_absolute = secclock () + Dfile_wait_relative;
  1822.     if (Dfile_upd && Dfile_updater == NULLPROC) {
  1823.         Dfile_updater = newproc ("domain update",
  1824.                       1024, dfile_update, 0, NULL, NULL, 0);
  1825.     }
  1826. #ifdef DEBUG
  1827.     if (Dtrace)
  1828.         keywait (NULLCHAR, 1);    /* so we can look around */
  1829. #endif
  1830.     free ((char *) dhp);
  1831.     return;
  1832. }
  1833.  
  1834.  
  1835.  
  1836. /**
  1837.  **     Resolver Utilities
  1838.  **/
  1839.  
  1840. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1841.  * return FALSE otherwise (i.e., if string is a domain name)
  1842.  */
  1843. static int
  1844. isaddr (register const char *s)
  1845. {
  1846. char c;
  1847.  
  1848.     if (s == NULLCHAR)
  1849.         return TRUE;    /* Can't happen */
  1850.  
  1851.     while ((c = *s++) != '\0') {
  1852.         if (c != '[' && c != ']' && !isdigit (c) && c != '.')
  1853.             return FALSE;
  1854.     }
  1855.     return TRUE;
  1856. }
  1857.  
  1858.  
  1859.  
  1860. /* Search for resource records.
  1861.  * Returns RR list, or NULLRR if no record found.
  1862.  */
  1863. static struct rr *
  1864. resolver (register struct rr *rrlp)
  1865. {
  1866. register struct rr *result_rrlp;
  1867. struct rr *lrrp, *nrrp, *xrrp;
  1868.  
  1869.     if ((result_rrlp = dcache_search (rrlp)) == NULLRR)
  1870.         result_rrlp = dfile_search (rrlp);
  1871.  
  1872.     if (result_rrlp == NULLRR || check_ttl (result_rrlp) != 0) {
  1873.         if (!DTransing || !DLTranslate) {
  1874.             dcache_add (result_rrlp);    /* save any expired RRs */
  1875.             dns_query (rrlp);
  1876.             result_rrlp = dcache_search (rrlp);
  1877.         }
  1878.     }
  1879.     dcache_add (copy_rr_list (result_rrlp));
  1880.     /* N5KNX: dns_query() will store negative replies into the cache, so we must
  1881.        take care never to return them in the list of (valid) records. */
  1882.     xrrp = result_rrlp;
  1883.     lrrp = NULLRR;
  1884.     while(xrrp) {
  1885.         nrrp = xrrp->next;
  1886.         if (!(xrrp->rdlength)) {  /* remove it from list */
  1887.             if (lrrp)
  1888.                 lrrp->next = nrrp;
  1889.             else
  1890.                 result_rrlp = nrrp;
  1891.             xrrp->next = NULLRR;
  1892.             free_rr(xrrp);
  1893.         } else
  1894.             lrrp = xrrp;
  1895.         xrrp = nrrp;
  1896.     }
  1897.         
  1898.     return result_rrlp;
  1899. }
  1900.  
  1901.  
  1902.  
  1903. /* general entry point for address -> domain name resolution.
  1904.  * Returns RR list, or NULLRR if no record found.
  1905.  */
  1906. struct rr *
  1907. inverse_a (uint32 ip_address)
  1908. {
  1909. struct rr *prrp;
  1910. struct rr *result_rrlp;
  1911. char pname[34];
  1912.  
  1913.     if (ip_address == 0L)
  1914.         return NULLRR;
  1915.  
  1916.     sprintf (pname, "%u.%u.%u.%u.IN-ADDR.ARPA.", lobyte (loword (ip_address)),
  1917.         hibyte (loword (ip_address)), lobyte (hiword (ip_address)),
  1918.         hibyte (hiword (ip_address)));
  1919.  
  1920.     prrp = make_rr (RR_QUERY, pname, CLASS_IN, TYPE_PTR, 0, 0, NULL);
  1921.  
  1922.     /* make list to speed search */
  1923.     prrp->next = make_rr (RR_INQUERY, NULLCHAR, CLASS_IN, TYPE_A, 0, 4, &ip_address);
  1924.  
  1925.     result_rrlp = resolver (prrp);
  1926.  
  1927.     free_rr (prrp);
  1928.     return result_rrlp;
  1929. }
  1930.  
  1931.  
  1932.  
  1933. /* general entry point for domain name -> resource resolution.
  1934.  * Returns RR list, or NULLRR if no record found.
  1935.  */
  1936. /* Optional recursive search to resolve CNAME records that
  1937.    prevents proper handling of CNAME queries.  Forces recursion to take
  1938.    place only at the resolver of the node originating the query.
  1939.    Modification introducted by Don Sandstrom, KG7CP, October 15, 1992.
  1940.    Additional mod by WG7J .
  1941.    Mod by N5KNX to return CNAME + associated A record when possible, if recurse==0.
  1942.    This makes it a better DNS server.
  1943.    */
  1944.  
  1945. static struct rr *
  1946. resolve_rr (const char *dname, int16 dtype, int recurse)
  1947. {
  1948. struct rr *prrp,*qrrp,*xrrp = NULLRR,*lrrp = NULLRR;
  1949. struct rr *result_rrlp = NULLRR;
  1950. char *sname;
  1951. int looping;
  1952.  
  1953.     if (dname == NULLCHAR)
  1954.         return NULLRR;
  1955.  
  1956.     sname = domainsuffix (dname);
  1957.     qrrp = make_rr (RR_QUERY, sname, CLASS_IN, dtype, 0, 0, NULL);
  1958.     free (sname);
  1959.  
  1960.     looping = MAXCNAME;
  1961.     if (!recurse) {
  1962.         result_rrlp = resolver (qrrp);
  1963.         prrp = result_rrlp;
  1964.         while (prrp) {
  1965.             if (looping == MAXCNAME && prrp->type != dtype && dtype != TYPE_ANY) { /* CNAME || PTR */
  1966.                 /* try once to expand to an A record */
  1967.                 xrrp = resolve_rr (prrp->rdata.name, TYPE_A, 1);
  1968.                 looping--;
  1969.             }
  1970.             lrrp = prrp;
  1971.             prrp = prrp->next;
  1972.         }
  1973.         if (looping != MAXCNAME)    /* did we expand a CNAME/PTR record? */
  1974.             lrrp->next = xrrp;   /*lint !e794 * add to end of result chain */
  1975. #ifdef DEBUG
  1976.         if (Dtrace)
  1977.             put_rr (stdout, result_rrlp);
  1978. #endif
  1979.     } else {
  1980.         while (looping > 0) {
  1981.             if ((result_rrlp = resolver (qrrp)) == NULLRR || result_rrlp->type == dtype)
  1982.                 break;
  1983. #ifdef DEBUG
  1984.             if (Dtrace)
  1985.                 put_rr (stdout, result_rrlp);
  1986. #endif
  1987.             /* Should be CNAME or PTR record */
  1988.             /* Replace name and try again */
  1989.             free (qrrp->name);
  1990.             qrrp->name = strdup (result_rrlp->rdata.name);
  1991.             free_rr (result_rrlp);
  1992.             result_rrlp = NULLRR;
  1993.             looping--;
  1994.         }
  1995.     }
  1996.     free_rr (qrrp);
  1997.     return result_rrlp;
  1998. }
  1999.  
  2000.  
  2001.  
  2002. /* main entry point for address -> domain name resolution.
  2003.  * Returns string, or NULLCHAR if no name found.
  2004.  */
  2005. char *
  2006. resolve_a (ip_address, shorten)
  2007. uint32 ip_address;        /* search address */
  2008. int shorten;            /* return only first part of name (flag)*/
  2009. {
  2010. struct rr *save_rrlp, *rrlp;
  2011. char *result = NULLCHAR, *p;
  2012.  
  2013. /* N7IPB - When we have a lot of unresolvable addresses such as subnet routes in
  2014.  *         the routing table, domain translation can take a long time.  The
  2015.  *         following allows us to skip the translation process for any address
  2016.  *         ending in .000 or .255.  These are assumed to be either subnets or
  2017.  *         broadcast addresses.  Can be turned on and off with the 'domain subnet'
  2018.  *         command.
  2019.  */
  2020.  
  2021.     DTransing = 1;
  2022.     if (((ip_address & 0x0ff) && ((ip_address & 0x0ff) ^ 0x0ff)) || Dsubnet_translate) {
  2023.         for (rrlp = save_rrlp = inverse_a (ip_address);
  2024.              rrlp != NULLRR && result == NULLCHAR;
  2025.              rrlp = rrlp->next) {
  2026.             if (rrlp->rdlength > 0) {
  2027.                 switch (rrlp->type) {
  2028.                     case TYPE_PTR:
  2029.                         result = strdup (rrlp->rdata.name);
  2030.                         break;
  2031.                     case TYPE_A:
  2032.                         result = strdup (rrlp->name);
  2033.                         break;
  2034.                     default:
  2035.                         break;
  2036.                 }
  2037.             }
  2038.         }
  2039.         free_rr (save_rrlp);
  2040.  
  2041.         /* From Dennis Goodwin, kb7dz.
  2042.          * when domain verbose is off,
  2043.          * this make a domain name line bbs.wg7j.ampr.org show as bbs.wg7j
  2044.          * as opposed to bbs, as the above code does.
  2045.          */
  2046.         if (result != NULLCHAR && shorten) {
  2047.             if (Dsuffix != NULLCHAR)
  2048.                 /* domain name minus domain suffix */
  2049.                 p = strstr (result, Dsuffix);
  2050.             else    {
  2051.                 /* domain name up to, and including the first period */
  2052.                 p = strchr (result, '.');
  2053.                 if (p != NULLCHAR)
  2054.                     p++;
  2055.             }
  2056.             if (p != NULLCHAR)
  2057.                 *p = '\0';
  2058.         }
  2059.         if (result != NULLCHAR && *result) {
  2060.             /* remove trailing . */
  2061.             for (p = result; *p; ++p)
  2062.                 ;
  2063.             if (*(--p) == '.')
  2064.                 *p = (char) 0;
  2065.         }
  2066.         /* end of mod */
  2067.     }
  2068.     DTransing = 0;
  2069.     return result;
  2070. }
  2071.  
  2072.  
  2073.  
  2074. /* Main entry point for domain name -> address resolution.
  2075.  * Returns 0 if name is currently unresolvable.
  2076.  */
  2077. uint32
  2078. resolve (const char *name)
  2079. {
  2080. register struct rr *rrlp;
  2081. uint32 ip_address = 0;
  2082.  
  2083.     if (name == NULLCHAR || strlen(name) == 0)
  2084.         return 0;
  2085.  
  2086.     if (isaddr (name))
  2087.         return aton (name);
  2088.  
  2089.     if ((rrlp = resolve_rr (name, TYPE_A, 1)) != NULLRR && rrlp->rdlength > 0)
  2090.         ip_address = rrlp->rdata.addr;
  2091.  
  2092.     /* multi-homed hosts are handled here */
  2093.     if (rrlp != NULLRR && rrlp->next != NULLRR) {
  2094.         register struct rr *rrp;
  2095.         register struct route *rp;
  2096.         int16 cost = MAXINT16;
  2097.  
  2098.         rrp = rrlp;
  2099.         while (rrp != NULLRR) {    /* choose the best of a set of routes */
  2100.             if (rrp->rdlength > 0 && (rp = rt_lookup (rrp->rdata.addr)) != NULLROUTE && rp->metric <= cost) {
  2101.                 ip_address = rrp->rdata.addr;
  2102.                 cost = (int16) rp->metric;
  2103.             }
  2104.             rrp = rrp->next;
  2105.         }
  2106.     }
  2107.     free_rr (rrlp);
  2108.     return ip_address;
  2109. }
  2110.  
  2111.  
  2112.  
  2113. /* Lookup alternative MX records. Upto 5 of them. -- Selcuk */
  2114. int
  2115. resolve_amx (char *name, uint32 not_this_one, uint32 Altmx[])
  2116. {
  2117. register struct rr *rrp, *arrp;
  2118. char *sname;
  2119. uint32 addr;
  2120. int16 exists = 0, i, n, tmp[5];
  2121.  
  2122.     if (name == NULLCHAR)
  2123.         return exists;
  2124.  
  2125.     if (isaddr (name)) {
  2126.         if ((sname = resolve_a (aton (name), FALSE)) == NULLCHAR)
  2127.             return exists;
  2128.     } else
  2129.         sname = strdup (name);
  2130.  
  2131.     for (i = 0; i < 5; i++) {    /* let's initialize */
  2132.         tmp[i] = MAXINT16;
  2133.         Altmx[i] = 0L;
  2134.     }
  2135.  
  2136.     i = 0;
  2137.     rrp = arrp = resolve_rr (sname, TYPE_MX, 1);
  2138.     /* Search this list of rr's for an MX record */
  2139.     while (rrp != NULLRR) {
  2140.         if (rrp->rdlength > 0 && (addr = resolve (rrp->rdata.mx.exch)) != 0L && addr != not_this_one) {
  2141.             for (n = i;; n--) {
  2142.                 if (n > 0 && rrp->rdata.mx.pref < tmp[n - 1]) {
  2143.                     tmp[n] = tmp[n - 1];
  2144.                     Altmx[n] = Altmx[n - 1];
  2145.                 } else {
  2146.                     if (rrp->rdata.mx.pref < tmp[n]) {
  2147.                         tmp[n] = rrp->rdata.mx.pref;
  2148.                         Altmx[n] = addr;
  2149.                         exists++;
  2150.                     }
  2151.                     break;
  2152.                 }
  2153.             }
  2154.             if (i < 4)
  2155.                 i++;
  2156.         }
  2157.         rrp = rrp->next;
  2158.     }
  2159.     free_rr (arrp);
  2160.  
  2161.     free (sname);
  2162.     return exists;
  2163. }
  2164.  
  2165.  
  2166.  
  2167. /* Main entry point for MX record lookup.
  2168.  * Returns 0 if name is currently unresolvable.
  2169.  *
  2170.  * TODO: If we have MX records of equal cost, we should randomize which
  2171.  * one we select.
  2172.  */
  2173. uint32
  2174. resolve_mx (const char *name)
  2175. {
  2176. register struct rr *rrp, *arrp;
  2177. char *sname, *tmp, *cp;
  2178. uint32 addr, ip_address = 0;
  2179. int16 pref = MAXINT16;
  2180. int16 localpref = MAXINT16;
  2181.  
  2182.     if (name == NULLCHAR)
  2183.         return 0;
  2184.  
  2185.     if (isaddr (name)) {
  2186.         if ((sname = resolve_a (aton (name), FALSE)) == NULLCHAR)
  2187.             return 0;
  2188.     } else
  2189.         sname = strdup (name);
  2190.  
  2191.     cp = sname;
  2192.     for ( ; ; ) {
  2193.         rrp = arrp = resolve_rr (sname, TYPE_MX, 1);
  2194.         /* Search this list of rr's for an MX record */
  2195.         while (rrp != NULLRR) {
  2196.             if (rrp->rdlength > 0) {
  2197.                 addr = resolve (rrp->rdata.mx.exch);
  2198.                 /*
  2199.                  * If this is one of our interfaces,
  2200.                  * report our master IP address to avoid
  2201.                  * mail loops.  Also record our preference.
  2202.                  */
  2203.                 if (ismyaddr (addr)) {
  2204.                     addr = Ip_addr;
  2205.                     if (rrp->rdata.mx.pref < localpref)
  2206.                         localpref = rrp->rdata.mx.pref;
  2207.                 }
  2208.                 if (rrp->rdata.mx.pref < pref) {
  2209.                     pref = rrp->rdata.mx.pref;
  2210.                     ip_address = addr;
  2211.                 }
  2212.             }
  2213.             rrp = rrp->next;
  2214.         }
  2215.         free_rr (arrp);
  2216.         if (ip_address != 0)
  2217.             break;
  2218.         /* Compose wild card one level up */
  2219.         if ((cp = strchr (cp, '.')) == NULLCHAR)
  2220.             break;
  2221.         tmp = mallocw (strlen (cp) + 2);
  2222.         sprintf (tmp, "*%s", cp);    /* wildcard expansion */
  2223.         free (sname);
  2224.         sname = tmp;
  2225.         cp = sname + 2;
  2226.     }
  2227.     free (sname);
  2228.  
  2229.     /*
  2230.      * If the best MX record we found is not better than ourselves, then
  2231.      * there are no valid MX hosts we should consider.
  2232.      */
  2233.     if (pref > localpref)
  2234.         ip_address = 0;
  2235.  
  2236.     return ip_address;
  2237. }
  2238.  
  2239.  
  2240.  
  2241. /* Search for local records of the MB, MG and MR type. Returns list of
  2242.  * matching records.
  2243.  */
  2244. struct rr *
  2245. resolve_mailb (name)
  2246. const char *name;        /* local username, without trailing dot */
  2247. {
  2248. register struct rr *result_rrlp;
  2249. struct rr *rrlp;
  2250. char *sname;
  2251.  
  2252.     sname = strdup (name);
  2253.     rrlp = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MB, 0, 0, NULL);
  2254.     rrlp->next = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MG, 0, 0, NULL);
  2255.     rrlp->next->next = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MR, 0, 0, NULL);
  2256.     free (sname);
  2257.     if ((result_rrlp = dcache_search (rrlp)) == NULLRR)
  2258.         result_rrlp = dfile_search (rrlp);
  2259.  
  2260.     free_rr (rrlp);
  2261.     if (Dsuffix != NULLCHAR) {
  2262.         rrlp = result_rrlp;
  2263.         while (rrlp != NULLRR) {    /* add domain suffix to data */
  2264.             if (rrlp->rdlength > 0 &&
  2265.                 rrlp->rdata.name[rrlp->rdlength - 1] != '.') {
  2266.                 sname = mallocw ((unsigned) (rrlp->rdlength +
  2267.                                  Dsuffixl + 2));
  2268.                 sprintf (sname, "%s.%s", rrlp->rdata.name, Dsuffix);
  2269.                 free (rrlp->rdata.name);
  2270.                 rrlp->rdata.name = sname;
  2271.                 rrlp->rdlength = (int16) strlen (sname);
  2272.             }
  2273.             rrlp = rrlp->next;
  2274.         }
  2275.     }
  2276.     dcache_add (copy_rr_list (result_rrlp));
  2277.     return result_rrlp;
  2278. }
  2279.  
  2280.  
  2281.  
  2282. /* Return "normalized" domain name, with default suffix and trailing '.'
  2283.  * Searches local cache for CNAME expansions.
  2284.  */
  2285. char *
  2286. domainsuffix (const char *dname)
  2287. {
  2288. char *sname, *tname, *pp;
  2289. int l;
  2290.  
  2291.     if (dname == NULLCHAR)
  2292.         return NULLCHAR;
  2293.  
  2294.     if (isaddr (dname))
  2295.         /* convert to our canonic form */
  2296.         return strdup (inet_ntoa (aton (dname)));
  2297.  
  2298.     sname = strdup (dname);
  2299.     l = (int) strlen (sname);
  2300.     if ((pp = strrchr (sname, '.')) == NULLCHAR) {
  2301.         /* No dot in name. Try to add default suffix */
  2302.         if (Dsuffix != NULLCHAR) {
  2303.             /* Append default suffix */
  2304.             tname = mallocw ((unsigned) (l + Dsuffixl + 2));
  2305.             sprintf (tname, "%s.%s", sname, Dsuffix);
  2306.             free (sname);
  2307.             sname = tname;
  2308.         }
  2309.     } else {
  2310.         /* There is a dot in the name. Check last part of
  2311.          * name. If longer than 4 char it must be a name
  2312.          * 4 or less is probably a domain (org, army, uk)
  2313.          */
  2314.         if (Dsuffix != NULLCHAR) {
  2315.             if (strlen (pp) <= 5) {
  2316.                 for (++pp; *pp; pp++) {
  2317.                     if (isdigit (*pp))
  2318.                         break;
  2319.                 }
  2320.                 if (*pp) {
  2321.                     /* Append default suffix */
  2322.                     tname = mallocw ((unsigned) (l + Dsuffixl + 2));
  2323.                     sprintf (tname, "%s.%s", sname, Dsuffix);
  2324.                     free (sname);
  2325.                     sname = tname;
  2326.                 }
  2327.             } else {
  2328.                 /* name with dot (must be call + local domain) */
  2329.                 tname = mallocw ((unsigned) (l + Dsuffixl + 2));
  2330.                 sprintf (tname, "%s.%s", sname, Dsuffix);
  2331.                 free (sname);
  2332.                 sname = tname;
  2333.             }
  2334.         }
  2335.     }
  2336.  
  2337.     if (sname[strlen (sname) - 1] != '.') {
  2338.         /* Append trailing dot */
  2339.         tname = mallocw (strlen (sname) + 2);
  2340.         sprintf (tname, "%s.", sname);
  2341.         free (sname);
  2342.         sname = tname;
  2343.     }
  2344.     return sname;
  2345. }
  2346.  
  2347.  
  2348.  
  2349. #ifdef DSERVER
  2350.  
  2351. /* Domain Name Server - based on the server in GRI-Nos 910828
  2352.  * ported to current NOS code by Johan. K. Reinalda, WG7J/PA3DIS
  2353.  *
  2354.  * - Does not answer more then one query per frame
  2355.  * - Gives non-authoritative answers to all queries.
  2356.  * - Does not reply with authority or additional RR's
  2357.  * - If no answers are found in local cache or domain.txt file,
  2358.  *   remote servers, if configured, are queried.
  2359.  *
  2360.  *
  2361.  * v0.93  10/19/92   queries do not recurse anymore, but let the requester
  2362.  *                   do the recursion (Solves problem with CNAME queries)
  2363.  * v0.92  06/24/92   RR length bug fixed.
  2364.  *                   A,CNAME,MX,HINFO,PTR,NS,SOA queries now work
  2365.  * v0.91  06/22/92   MX has small bug with RR length indication
  2366.  * v0.90  06/20/92   Only supports a single type 'A' request per frame
  2367.  */
  2368.  
  2369. static int Dsocket = -1;
  2370.  
  2371. /* Process a query received by the DNS server */
  2372. static void
  2373. proc_query (int unused OPTIONAL, void *d, void *b)
  2374. {
  2375. struct dserver *dp;
  2376. struct dhdr *dhdr;
  2377. int i, len;
  2378. char *buf;
  2379. struct sockaddr_in server;
  2380. struct rr *rrp, *rrans, *rrtmp;
  2381. struct rr *qp;
  2382.  
  2383.     dp = (struct dserver *) d;    /* The query address */
  2384.     dhdr = (struct dhdr *) b;    /* The query in host format */
  2385.  
  2386.     rrans = NULLRR;
  2387.     qp = dhdr->questions;
  2388.  
  2389.     /* This does NOT loop and support multiple questions yet */
  2390.  
  2391.     dhdr->aa = 0;
  2392.     switch (qp->type) {
  2393.         case TYPE_A:
  2394.         case TYPE_MX:
  2395.         case TYPE_CNAME:
  2396.         case TYPE_HINFO:
  2397.         case TYPE_PTR:
  2398.         case TYPE_NS:
  2399.         case TYPE_SOA:
  2400.             /* Not all of the below types are implemented in resolve_rr() */
  2401.             /* Let the other side resolve CNAME references, do not recurse ! */
  2402.             if ((rrp = resolve_rr (qp->name, qp->type, 0)) != NULLRR && rrp->rdlength > 0) {
  2403.                 /* we found an entry, go tell him */
  2404.                 dhdr->rcode = NO_ERROR;
  2405.                 dhdr->qr = RESPONSE;
  2406.             } else {
  2407.                 /* we did not find an entry, go tell him */
  2408.                 free_rr (rrp);    /* in case rdlength==0 */
  2409.                 rrp = (struct rr *) callocw (1, sizeof (struct rr));
  2410.  
  2411.                 rrp->name = strdup (qp->name);
  2412.                 rrp->type = qp->type;
  2413.                 rrp->class = qp->class;
  2414.                 rrp->ttl = 500L;
  2415.                 rrp->rdata.addr = 0L;
  2416.                 rrp->rdlength = 4;    /* size of addr data */
  2417.                 dhdr->rcode = NAME_ERROR;
  2418.                 dhdr->qr = RESPONSE;
  2419.             }
  2420.             rrans = rrp;
  2421.             break;
  2422.             /* Search only the local cache and domain file for these next few */
  2423.             /* Is this a good idea ??? */
  2424.         case TYPE_MB:
  2425.         case TYPE_MG:
  2426.         case TYPE_MR:
  2427.             rrp = make_rr (RR_QUERY, qp->name, CLASS_IN, qp->type, 0, 0, NULL);
  2428.             if ((rrans = dcache_search (rrp)) == NULLRR)
  2429.                 rrans = dfile_search (rrp);
  2430.  
  2431.             free_rr (rrp);
  2432.             break;
  2433.         default:
  2434.             dhdr->rcode = NOT_IMPL;
  2435.             dhdr->qr = RESPONSE;
  2436.     }
  2437.  
  2438.     /* Find the number of answer records */
  2439.     i = 0;
  2440.     rrtmp = rrans;
  2441.     while (rrtmp != NULLRR) {
  2442.         i++;
  2443.         /* KG7CP -  - if no ttl in database, set the time-to-live value for
  2444.          * dns responses, unless no ttl value has been defined.
  2445.          */
  2446.         if (rrtmp->ttl == (int32) TTL_MISSING && Dns_ttl > 0L)
  2447.             rrtmp->ttl = Dns_ttl;
  2448.         rrtmp = rrtmp->next;
  2449.     }
  2450.     dhdr->ancount = (int16) i;
  2451.     dhdr->answers = rrans;
  2452.  
  2453.     /* Authority and Additional RR's not implemented yet. */
  2454.     dhdr->nscount = 0;
  2455.     dhdr->authority = NULLRR;
  2456.     dhdr->arcount = 0;
  2457.     dhdr->additional = NULLRR;
  2458.     dhdr->ra = 0;  /* recursion NOT available */
  2459.  
  2460.     if (Dtrace) {
  2461.         tcmdprintf ("DNS: replying");
  2462.         dumpdomain (dhdr, 0);
  2463.     }
  2464.     /* Maximum reply size is 512, see rfc1034/1035 */
  2465.     /*    buf = mallocw(512);    */
  2466.     buf = mallocw (5120);    /* quick patch */
  2467.     len = htondomain (dhdr, buf, 5120);
  2468.     if (len > 5120)  /* insufficient buffer space, we've trashed the arena */
  2469.         where_outta_here (1, "proc_query");
  2470.  
  2471.     free_dhdr (dhdr);
  2472.  
  2473.     server.sin_family = AF_INET;
  2474.     server.sin_port = dp->port;
  2475.     server.sin_addr.s_addr = dp->address;
  2476.     (void) sendto (Dsocket, buf, len, 0, (char *) &server, sizeof (server));
  2477.     free (buf);
  2478.     free ((char *) dp);
  2479.     dns_process_count--;
  2480. }
  2481.  
  2482.  
  2483.  
  2484. /* Process to receive all domain server related messages */
  2485. static void
  2486. drx (int unused OPTIONAL, void *u OPTIONAL, void *p OPTIONAL)
  2487. {
  2488. struct sockaddr_in sock, from;
  2489. int fromlen;
  2490. struct mbuf *bp;
  2491. struct dhdr *dhdr;
  2492. struct dserver *dp;
  2493. int foo;
  2494.  
  2495.     server_disconnect_io ();
  2496.     Dsocket = socket (AF_INET, SOCK_DGRAM, 0);
  2497.     sock.sin_family = AF_INET;
  2498.     sock.sin_addr.s_addr = INADDR_ANY;
  2499.     sock.sin_port = IPPORT_DOMAIN;
  2500.     if (bind (Dsocket, (char *) &sock, sizeof (sock)) == -1) {
  2501.         tputs ("DNS: can't bind\n");
  2502.         Dsocket = -1;
  2503.         return;
  2504.     }
  2505.     /* Now loop forever, processing queries */
  2506.     for (;;) {
  2507.         fromlen = sizeof (from);
  2508.         if ((foo = recv_mbuf (Dsocket, &bp, 0, (char *) &from, &fromlen)) == -1)
  2509.             break;    /* Server closing */
  2510.         if (foo == 0)
  2511.             continue;
  2512.         dhdr = mallocw (sizeof (struct dhdr));
  2513.  
  2514.         (void) ntohdomain (dhdr, &bp);
  2515.         if (Dtrace) {
  2516.             tcmdprintf ("DNS: %u bytes from %s\n", foo, psocket ((struct sockaddr *) &from));
  2517.             dumpdomain (dhdr, 0);
  2518.         }
  2519.         if (dns_process_count >= dns_maxcli) {    /* G8FSL */
  2520.             if (Dtrace)
  2521.                 tcmdprintf ("DNS: ignored - too many processes\n");
  2522.             free_dhdr (dhdr);
  2523.             continue;
  2524.         }
  2525.         dns_process_count++;
  2526.         /* Process queries only */
  2527.         if (dhdr->qr == QUERY) {
  2528.             /* Queries from ourself will cause a loop ! */
  2529.             if (ismyaddr (from.sin_addr.s_addr) != NULLIF) {
  2530.                 if (Dtrace)
  2531.                     tcmdprintf ("DNS: question from myself ignored\n");
  2532.                 free_dhdr (dhdr);
  2533.                 dns_process_count--;
  2534.                 continue;
  2535.             } else {
  2536.                 dp = (struct dserver *) callocw (1, sizeof (struct dserver));
  2537.  
  2538.                 dp->address = from.sin_addr.s_addr;
  2539.                 dp->srtt = (Dserver_maxwait * 1000L) / MSPTICK;
  2540.                 dp->timeout = dp->srtt * 2;
  2541.                 dp->port = from.sin_port;
  2542.                 if (dhdr->opcode == ZONEINIT) {
  2543.                     /* ZONEINIT not implemented */
  2544.                     free_dhdr (dhdr);
  2545.                     free (dp);
  2546.                 } else
  2547.                     (void) newproc ("Domain server", 1024, proc_query, 0, (void *) dp, (void *) dhdr, 0);
  2548.             }
  2549.         }
  2550.     }
  2551. }
  2552.  
  2553.  
  2554.  
  2555. static int
  2556. dodnsserver (int argc, char *argv[], void *p OPTIONAL)
  2557. {
  2558.     if (argc == 1)
  2559.         tprintf ("Domain Nameserver: O%s\n", (Dsocket != -1) ? "n" : "ff");
  2560.     else {
  2561.         if (!stricmp (argv[1], "on")) {
  2562.             if (Dsocket == -1)
  2563.                 /* Start domain server task */
  2564.                 (void) newproc ("Domain listener", 1024, drx, 0, NULL, NULL, 0);
  2565.         } else {
  2566.             close_s (Dsocket);
  2567.             Dsocket = -1;
  2568.         }
  2569.     }
  2570.     return 0;
  2571. }
  2572.  
  2573.  
  2574.  
  2575. /* Free a domain message */
  2576. static void
  2577. free_dhdr (struct dhdr *dp)
  2578. {
  2579.     if (dp->qdcount != 0)
  2580.         free_rr (dp->questions);
  2581.     if (dp->ancount != 0)
  2582.         free_rr (dp->answers);
  2583.     if (dp->nscount != 0)
  2584.         free_rr (dp->authority);
  2585.     if (dp->arcount != 0)
  2586.         free_rr (dp->additional);
  2587.     free ((char *) dp);
  2588. }
  2589.  
  2590.  
  2591.  
  2592. static int
  2593. dodnsmaxcli (int argc, char *argv[], void *p OPTIONAL)
  2594. {
  2595.     return setint (&dns_maxcli, "max. simultaneous DNS processes", argc, argv);
  2596. }
  2597.  
  2598.  
  2599.  
  2600. /* Resolves a name using local cache,
  2601.    local domain file or DNS if configured
  2602.    Updates local cache with result
  2603.    WA3DSP 12/93
  2604. */
  2605. static int
  2606. dodomresolve (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  2607. {
  2608. struct session *sp = (struct session *) 0;
  2609. uint32 addr;
  2610. int trans;
  2611. int insession = 0;
  2612.  
  2613.     if (Curproc->input == Command->input) {
  2614.         if ((sp = newsession (argv[1], RESOLVE, 0)) == NULLSESSION) {
  2615.             tputs ("Cannot open session\n");
  2616.             return 1;
  2617.         } else
  2618.             insession = 1;
  2619.     }
  2620.     tprintf ("Resolving %s ...\n", argv[1]);
  2621.     if ((addr = resolve (argv[1])) == 0) {
  2622.         tprintf ("Host \"%s\" unresolvable\n", argv[1]);
  2623.         if (insession) {
  2624.             (void) keywait (NULLCHAR, 1);
  2625.             freesession (sp);
  2626.         }
  2627.         return 1;
  2628.     }
  2629.     trans = DTranslate;
  2630.  
  2631.     /* Force output to be hostname - K2MF */
  2632.     DTranslate = 1;
  2633.     tprintf ("%s =", inet_ntoa (addr));
  2634.  
  2635.     /* Force output to be numeric IP address */
  2636.     DTranslate = 0;
  2637.     tprintf (" %s\n", inet_ntoa (addr));
  2638.  
  2639.     /* Restore original state */
  2640.     DTranslate = trans;
  2641.     if (insession)
  2642.         (void) keywait (NULLCHAR, 1);
  2643.     freesession (sp);
  2644.     return 0;
  2645. }
  2646.  
  2647.  
  2648.  
  2649. /* Domain Query a specific DNS for a name
  2650.    Does NOT update local cache or domain file
  2651.    "domain query ucsd.edu wa3dsp.ampr.org [type] [maxtries] [timeout-ms]"
  2652.    WA3DSP 12/93
  2653. */
  2654. static int
  2655. dodnsquery (int argc, char *argv[], void *p)
  2656. {
  2657. struct session *sp = (struct session *) 0;
  2658. struct mbuf *bp;
  2659. struct dhdr *dhp;
  2660. struct rr *qrrp;
  2661. struct rr *rrp;
  2662. struct sockaddr_in server_in;
  2663. uint32 address, ip_address;
  2664. int32 rtt, timeout, y;
  2665. int insession = 0, len, s, rval = 0, maxtries, x, count = 0;
  2666. int i, Type = 0;
  2667. char *sname, *buf;
  2668. char tmpname[80], rec_type[20];
  2669. char **margv;
  2670. FILE *fp;
  2671.  
  2672.     if (!Mprunning)    {
  2673.         Mprunning_err = 1;
  2674.         return 1;
  2675.     }
  2676.  
  2677.     if (Curproc->input == Command->input) {
  2678.         if ((sp = newsession (argv[1], DNSQUERY, 0)) == NULLSESSION) {
  2679.             tputs ("Cannot open session\n");
  2680.             return 1;
  2681.         } else
  2682.             insession = 1;
  2683.     }
  2684.     tprintf ("Resolving %s .....\n", argv[1]);
  2685.     if ((address = resolve (argv[1])) == 0L) {
  2686.         tprintf (Badhost, "Domain Nameserver", argv[1]);
  2687.         goto exit;
  2688.     }
  2689.     if (argc > 3) {
  2690.         strncpy (rec_type, argv[3], 20);
  2691.         (void) strupr (rec_type);
  2692.  
  2693.         for (i = 1; i < NDTYPES1; i += 2) {
  2694.             if (stricmp (rec_type, Dtypes1[i]) == 0) {
  2695.                 Type = atoi (Dtypes1[i]);
  2696.                 break;
  2697.             }
  2698.         }
  2699.  
  2700.         if (!Type) {
  2701.             tprintf ("Invalid type %s\n", rec_type);
  2702.             goto exit;
  2703.         }
  2704.     }
  2705.     if (isaddr (argv[2])) {
  2706.         ip_address = aton (argv[2]);
  2707.         sprintf (tmpname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  2708.              lobyte (loword (ip_address)),
  2709.              hibyte (loword (ip_address)),
  2710.              lobyte (hiword (ip_address)),
  2711.              hibyte (hiword (ip_address)));
  2712.         if (!Type) {
  2713.             Type = TYPE_PTR;
  2714.             strcpy (rec_type, "PTR");
  2715.         }
  2716.         qrrp = make_rr (RR_QUERY, tmpname, CLASS_IN, (int16) Type, 0, 0, NULL);
  2717.     } else {
  2718.         sname = domainsuffix (argv[2]);
  2719.         if (!Type) {
  2720.             Type = TYPE_A;
  2721.             strcpy (rec_type, "A");
  2722.         }
  2723.         qrrp = make_rr (RR_QUERY, sname, CLASS_IN, (int16) Type, 0, 0, NULL);
  2724.         free (sname);
  2725.     }
  2726.  
  2727.     if (argc > 4) {
  2728.         int tmpi = atoi (argv[4]);
  2729.         x = (int) min (tmpi, 10);
  2730.         maxtries = (int) max (x, 1);
  2731.     } else
  2732.         maxtries = 3;
  2733.  
  2734.     if (argc > 5) {
  2735.         int32 tmpi = atol (argv[5]);
  2736.         y = (int32) min (tmpi, 200000L);
  2737.         timeout = (int32) max (y, 100L);
  2738.     } else
  2739.         timeout = 20000L;
  2740.  
  2741.     s = socket (AF_INET, SOCK_DGRAM, 0);
  2742.     server_in.sin_family = AF_INET;
  2743.     server_in.sin_port = IPPORT_DOMAIN;
  2744.     server_in.sin_addr.s_addr = address;
  2745.  
  2746.     tprintf ("Querying server (%s)\n    for \"%s\"  - timeout=%ldms  Maxtries=%d\n\n",
  2747.          inet_ntoa (address), qrrp->name, timeout, maxtries);
  2748.  
  2749.     buf = mallocw (512);
  2750.     len = dns_makequery (0, qrrp, buf, 512);
  2751.     for (x = 0; x < maxtries; x++) {
  2752.         (void) sendto (s, buf, len, 0, (char *) &server_in, sizeof (server_in));
  2753.  
  2754.         kalarm (timeout);
  2755.  
  2756.         /* Wait for something to happen */
  2757.         rval = recv_mbuf (s, &bp, 0, NULLCHAR, 0);
  2758.         kalarm (0L);
  2759.  
  2760.         if (Dtrace)
  2761.             tcmdprintf ("DNS_Query: Received message length %d, errno %d\n", rval, errno);
  2762.         if (rval > 0 || errno == EABORT)
  2763.             break;
  2764.     }
  2765.     free (buf);
  2766.     close_s (s);
  2767.  
  2768.     if (rval > 0 && errno != EABORT) {
  2769.         dhp = (struct dhdr *) mallocw (sizeof (struct dhdr));
  2770.  
  2771.         (void) ntohdomain (dhp, &bp);    /* convert to local format */
  2772.  
  2773.         rtt = (int32) ((int16) msclock () - dhp->id);
  2774.         tprintf ("Rtt to host %s = %ldms\n\n", argv[1], rtt);
  2775.         margv = (char **) callocw (2, sizeof (char *));
  2776.  
  2777.         (void) tmpnam (tmpname);
  2778.         fp = fopen (tmpname, WRITE_TEXT);
  2779.         if (fp != NULLFILE)    {
  2780.             for (rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next) {
  2781.                 count++;
  2782.                 put_rr (fp, rrp);
  2783.             }
  2784.             (void) fclose (fp);
  2785.         }
  2786.         free_dhdr (dhp);
  2787.         if (count) {
  2788.             margv[1] = strdup (tmpname);
  2789.             (void) morecmd (2, margv, p);
  2790.             free (margv[1]);
  2791.             free (margv);
  2792.         } else
  2793.             tprintf ("No type (%s) records found at host %s for %s\n", rec_type, argv[1], qrrp->name);
  2794.  
  2795.         unlink (tmpname);
  2796.  
  2797.     } else
  2798.         tputs ("No response from Server\n");
  2799.  
  2800.     free_rr (qrrp);
  2801.  
  2802. exit:
  2803.     if (insession) {
  2804.         (void) keywait (NULLCHAR, 1);
  2805.         freesession (sp);
  2806.     }
  2807.     return 0;
  2808. }
  2809. #endif /* DSERVER */
  2810.  
  2811.  
  2812.  
  2813. #ifdef ALLCMD
  2814. int
  2815. dodomlook (int argc OPTIONAL, char *argv[], void *p)
  2816. {
  2817. char **margv;
  2818.  
  2819.     margv = (char **) callocw (3, sizeof (char *));
  2820.  
  2821.     margv[1] = strdup (DomainFile);
  2822.     margv[2] = strdup (argv[1]);
  2823.     (void) domore (3, margv, p);
  2824.     free (margv[1]);
  2825.     free (margv[2]);
  2826.     free (margv);
  2827.     return 0;
  2828. }
  2829.  
  2830. #endif
  2831.